mtproto 0.0.14 → 0.0.17
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/data/tl-schema.json +47158 -42684
- data/lib/mtproto/auth_key_generator.rb +2 -2
- data/lib/mtproto/client/api/export_authorization.rb +17 -0
- data/lib/mtproto/client/api/import_authorization.rb +23 -0
- data/lib/mtproto/client/api.rb +2 -0
- data/lib/mtproto/client/rpc.rb +33 -0
- data/lib/mtproto/client.rb +54 -1
- data/lib/mtproto/file_downloader.rb +122 -0
- data/lib/mtproto/tl/constructor_names.rb +324 -109
- data/lib/mtproto/tl/constructors.rb +16 -8
- data/lib/mtproto/tl/objects/bot_command_scope.rb +81 -0
- data/lib/mtproto/tl/objects/channels_join_channel.rb +1 -1
- data/lib/mtproto/tl/objects/channels_update_username.rb +42 -0
- data/lib/mtproto/tl/objects/contacts.rb +1 -1
- data/lib/mtproto/tl/objects/create_bot.rb +54 -0
- data/lib/mtproto/tl/objects/dialogs.rb +25 -10
- data/lib/mtproto/tl/objects/edit_access_settings.rb +46 -0
- data/lib/mtproto/tl/objects/export_authorization.rb +17 -0
- data/lib/mtproto/tl/objects/export_bot_token.rb +32 -0
- data/lib/mtproto/tl/objects/exported_authorization.rb +32 -0
- data/lib/mtproto/tl/objects/exported_bot_token.rb +27 -0
- data/lib/mtproto/tl/objects/forward_messages.rb +12 -3
- data/lib/mtproto/tl/objects/get_access_settings.rb +28 -0
- data/lib/mtproto/tl/objects/get_bot_callback_answer.rb +67 -0
- data/lib/mtproto/tl/objects/get_bot_commands.rb +46 -0
- data/lib/mtproto/tl/objects/get_file.rb +10 -2
- data/lib/mtproto/tl/objects/import_authorization.rb +38 -0
- data/lib/mtproto/tl/objects/input_keyboard_button_request_peer.rb +54 -0
- data/lib/mtproto/tl/objects/keyboard_button_callback.rb +50 -0
- data/lib/mtproto/tl/objects/message.rb +97 -21
- data/lib/mtproto/tl/objects/messages.rb +7 -74
- data/lib/mtproto/tl/objects/messages_get_messages.rb +26 -0
- data/lib/mtproto/tl/objects/reply_inline_markup.rb +30 -0
- data/lib/mtproto/tl/objects/reply_keyboard_markup.rb +35 -0
- data/lib/mtproto/tl/objects/request_peer_type_create_bot.rb +47 -0
- data/lib/mtproto/tl/objects/reset_bot_commands.rb +45 -0
- data/lib/mtproto/tl/objects/send_bot_requested_peer.rb +51 -0
- data/lib/mtproto/tl/objects/send_media.rb +87 -4
- data/lib/mtproto/tl/objects/send_message.rb +7 -2
- data/lib/mtproto/tl/objects/send_message_action.rb +48 -0
- data/lib/mtproto/tl/objects/set_bot_callback_answer.rb +54 -0
- data/lib/mtproto/tl/objects/set_bot_commands.rb +53 -0
- data/lib/mtproto/tl/objects/set_bot_guest_chat_result.rb +84 -0
- data/lib/mtproto/tl/objects/set_bot_info.rb +64 -0
- data/lib/mtproto/tl/objects/set_typing.rb +49 -0
- data/lib/mtproto/tl/objects/update_status.rb +24 -0
- data/lib/mtproto/tl/objects/updates.rb +117 -0
- data/lib/mtproto/tl/objects/updates_difference.rb +45 -69
- data/lib/mtproto/tl/objects/upload_profile_photo.rb +65 -0
- data/lib/mtproto/tl/reader.rb +188 -0
- data/lib/mtproto/transport/abridged_packet_codec.rb +5 -1
- data/lib/mtproto/unencrypted_message.rb +39 -0
- data/lib/mtproto/version.rb +1 -1
- data/lib/mtproto.rb +4 -1
- data/scripts/gen_constructor_names.rb +72 -0
- data/scripts/tl_to_json.rb +72 -0
- data/scripts/verify_ids.rb +33 -0
- metadata +38 -2
- data/lib/mtproto/message/message.rb +0 -85
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class SendBotRequestedPeer
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
CONSTRUCTOR = 0x6c5cf2a7
|
|
9
|
+
|
|
10
|
+
# peer / requested_peers entries: { type:, id:, access_hash: } or { type: :self }
|
|
11
|
+
def initialize(peer:, button_id:, msg_id: nil, requested_peers: [])
|
|
12
|
+
@peer = peer
|
|
13
|
+
@button_id = button_id
|
|
14
|
+
@msg_id = msg_id
|
|
15
|
+
@requested_peers = requested_peers
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def serialize
|
|
19
|
+
flags = 0
|
|
20
|
+
flags |= (1 << 0) if @msg_id
|
|
21
|
+
|
|
22
|
+
result = u32_b(CONSTRUCTOR)
|
|
23
|
+
result += u32_b(flags)
|
|
24
|
+
result += serialize_input_peer(@peer)
|
|
25
|
+
result += u32_b(@msg_id) if @msg_id
|
|
26
|
+
result += u32_b(@button_id)
|
|
27
|
+
result += u32_b(Constructors::VECTOR)
|
|
28
|
+
result += u32_b(@requested_peers.size)
|
|
29
|
+
@requested_peers.each { |peer| result += serialize_input_peer(peer) }
|
|
30
|
+
result
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def serialize_input_peer(peer)
|
|
36
|
+
case peer[:type]
|
|
37
|
+
when :self
|
|
38
|
+
u32_b(Constructors::INPUT_PEER_SELF)
|
|
39
|
+
when :user
|
|
40
|
+
u32_b(Constructors::INPUT_PEER_USER) + u64_b(peer[:id]) + u64_b(peer[:access_hash] || 0)
|
|
41
|
+
when :chat
|
|
42
|
+
u32_b(Constructors::INPUT_PEER_CHAT) + u64_b(peer[:id])
|
|
43
|
+
when :channel
|
|
44
|
+
u32_b(Constructors::INPUT_PEER_CHANNEL) + u64_b(peer[:id]) + u64_b(peer[:access_hash] || 0)
|
|
45
|
+
else
|
|
46
|
+
raise "Unknown peer type: #{peer[:type]}"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -7,17 +7,30 @@ module MTProto
|
|
|
7
7
|
class SendMedia
|
|
8
8
|
include Binary
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
INPUT_REPLY_TO_MESSAGE = 0x3bd4b7c2
|
|
11
|
+
INPUT_MEDIA_PHOTO = 0xe3af4434
|
|
12
|
+
INPUT_MEDIA_DOCUMENT = 0xa8763ab5
|
|
13
|
+
INPUT_PHOTO = 0x3bb3b94a
|
|
14
|
+
INPUT_DOCUMENT = 0x1abfb575
|
|
15
|
+
|
|
16
|
+
def initialize(peer:, media:, message: '', random_id: nil, reply_to: nil, silent: false)
|
|
11
17
|
@peer = peer
|
|
12
18
|
@media = media
|
|
13
19
|
@message = message
|
|
14
20
|
@random_id = random_id || SecureRandom.random_number(2**63)
|
|
21
|
+
@reply_to = reply_to
|
|
22
|
+
@silent = silent
|
|
15
23
|
end
|
|
16
24
|
|
|
17
25
|
def serialize
|
|
26
|
+
flags = 0
|
|
27
|
+
flags |= (1 << 0) if @reply_to
|
|
28
|
+
flags |= (1 << 5) if @silent
|
|
29
|
+
|
|
18
30
|
result = u32_b(Constructors::MESSAGES_SEND_MEDIA)
|
|
19
|
-
result += u32_b(
|
|
31
|
+
result += u32_b(flags)
|
|
20
32
|
result += serialize_input_peer
|
|
33
|
+
result += serialize_reply_to if @reply_to
|
|
21
34
|
result += serialize_input_media
|
|
22
35
|
result += serialize_tl_string(@message)
|
|
23
36
|
result += u64_b(@random_id)
|
|
@@ -26,6 +39,10 @@ module MTProto
|
|
|
26
39
|
|
|
27
40
|
private
|
|
28
41
|
|
|
42
|
+
def serialize_reply_to
|
|
43
|
+
u32_b(INPUT_REPLY_TO_MESSAGE) + u32_b(0) + u32_b(@reply_to)
|
|
44
|
+
end
|
|
45
|
+
|
|
29
46
|
def serialize_input_peer
|
|
30
47
|
case @peer[:type]
|
|
31
48
|
when :self
|
|
@@ -45,11 +62,27 @@ module MTProto
|
|
|
45
62
|
case @media[:type]
|
|
46
63
|
when :uploaded_photo
|
|
47
64
|
serialize_input_media_uploaded_photo(@media[:file])
|
|
65
|
+
when :uploaded_document
|
|
66
|
+
serialize_input_media_uploaded_document(@media)
|
|
67
|
+
when :photo
|
|
68
|
+
serialize_existing_media(INPUT_MEDIA_PHOTO, INPUT_PHOTO, @media)
|
|
69
|
+
when :document
|
|
70
|
+
serialize_existing_media(INPUT_MEDIA_DOCUMENT, INPUT_DOCUMENT, @media)
|
|
48
71
|
else
|
|
49
72
|
raise "Unknown media type: #{@media[:type]}"
|
|
50
73
|
end
|
|
51
74
|
end
|
|
52
75
|
|
|
76
|
+
# Re-send media that already lives on Telegram, by reference — inputMediaPhoto/
|
|
77
|
+
# inputMediaDocument (flags=0) wrapping inputPhoto/inputDocument(id, access_hash,
|
|
78
|
+
# file_reference). Used to re-post a guest-mention's photo/video, where the bot
|
|
79
|
+
# cannot forward from a chat it is not a member of.
|
|
80
|
+
def serialize_existing_media(media_ctor, input_ctor, media)
|
|
81
|
+
u32_b(media_ctor) + u32_b(0) +
|
|
82
|
+
u32_b(input_ctor) + u64_b(media[:id]) + u64_b(media[:access_hash]) +
|
|
83
|
+
serialize_bytes(media[:file_reference])
|
|
84
|
+
end
|
|
85
|
+
|
|
53
86
|
def serialize_input_media_uploaded_photo(file)
|
|
54
87
|
result = u32_b(Constructors::INPUT_MEDIA_UPLOADED_PHOTO)
|
|
55
88
|
result += u32_b(0) # flags
|
|
@@ -57,6 +90,48 @@ module MTProto
|
|
|
57
90
|
result
|
|
58
91
|
end
|
|
59
92
|
|
|
93
|
+
# inputMediaUploadedDocument with flags=0 (no thumb/stickers/ttl/video
|
|
94
|
+
# fields): file, mime_type, then the document-attributes vector. A generic
|
|
95
|
+
# file carries documentAttributeFilename; audio adds documentAttributeAudio.
|
|
96
|
+
def serialize_input_media_uploaded_document(media)
|
|
97
|
+
u32_b(Constructors::INPUT_MEDIA_UPLOADED_DOCUMENT) +
|
|
98
|
+
u32_b(0) +
|
|
99
|
+
serialize_input_file(media[:file]) +
|
|
100
|
+
serialize_tl_string(media[:mime_type].to_s) +
|
|
101
|
+
serialize_document_attributes(media[:attributes] || [])
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def serialize_document_attributes(attributes)
|
|
105
|
+
result = u32_b(Constructors::VECTOR) + u32_b(attributes.length)
|
|
106
|
+
attributes.each { |attribute| result += serialize_document_attribute(attribute) }
|
|
107
|
+
result
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def serialize_document_attribute(attribute)
|
|
111
|
+
case attribute[:type]
|
|
112
|
+
when :filename
|
|
113
|
+
u32_b(Constructors::DOCUMENT_ATTRIBUTE_FILENAME) +
|
|
114
|
+
serialize_tl_string(attribute[:file_name].to_s)
|
|
115
|
+
when :audio
|
|
116
|
+
serialize_document_attribute_audio(attribute)
|
|
117
|
+
else
|
|
118
|
+
raise "Unknown document attribute: #{attribute[:type]}"
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# documentAttributeAudio: voice=flags.10, title=flags.0, performer=flags.1;
|
|
123
|
+
# title is written before performer on the wire.
|
|
124
|
+
def serialize_document_attribute_audio(attribute)
|
|
125
|
+
flags = 0
|
|
126
|
+
flags |= (1 << 0) if attribute[:title]
|
|
127
|
+
flags |= (1 << 1) if attribute[:performer]
|
|
128
|
+
flags |= (1 << 10) if attribute[:voice]
|
|
129
|
+
result = u32_b(Constructors::DOCUMENT_ATTRIBUTE_AUDIO) + u32_b(flags) + u32_b(attribute[:duration].to_i)
|
|
130
|
+
result += serialize_tl_string(attribute[:title]) if attribute[:title]
|
|
131
|
+
result += serialize_tl_string(attribute[:performer]) if attribute[:performer]
|
|
132
|
+
result
|
|
133
|
+
end
|
|
134
|
+
|
|
60
135
|
def serialize_input_file(file)
|
|
61
136
|
u32_b(Constructors::INPUT_FILE) +
|
|
62
137
|
u64_b(file[:id]) +
|
|
@@ -66,9 +141,17 @@ module MTProto
|
|
|
66
141
|
end
|
|
67
142
|
|
|
68
143
|
def serialize_tl_string(str)
|
|
69
|
-
|
|
70
|
-
|
|
144
|
+
serialize_byte_array(str.encode('UTF-8').bytes)
|
|
145
|
+
end
|
|
71
146
|
|
|
147
|
+
# TL bytes for a raw binary string (e.g. a file_reference) — NOT re-encoded as
|
|
148
|
+
# UTF-8, which would corrupt arbitrary bytes.
|
|
149
|
+
def serialize_bytes(raw)
|
|
150
|
+
serialize_byte_array(raw.to_s.b.bytes)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def serialize_byte_array(bytes)
|
|
154
|
+
length = bytes.length
|
|
72
155
|
if length <= 253
|
|
73
156
|
[length] + bytes + padding(length + 1)
|
|
74
157
|
else
|
|
@@ -7,18 +7,22 @@ module MTProto
|
|
|
7
7
|
class SendMessage
|
|
8
8
|
include Binary
|
|
9
9
|
|
|
10
|
-
INPUT_REPLY_TO_MESSAGE =
|
|
10
|
+
INPUT_REPLY_TO_MESSAGE = 0x3bd4b7c2
|
|
11
11
|
|
|
12
|
-
def initialize(peer:, message:, random_id: nil, reply_to: nil)
|
|
12
|
+
def initialize(peer:, message:, random_id: nil, reply_to: nil, reply_markup: nil, silent: false)
|
|
13
13
|
@peer = peer
|
|
14
14
|
@message = message
|
|
15
15
|
@random_id = random_id || SecureRandom.random_number(2**63)
|
|
16
16
|
@reply_to = reply_to
|
|
17
|
+
@reply_markup = reply_markup
|
|
18
|
+
@silent = silent
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
def serialize
|
|
20
22
|
flags = 0
|
|
21
23
|
flags |= (1 << 0) if @reply_to
|
|
24
|
+
flags |= (1 << 2) if @reply_markup
|
|
25
|
+
flags |= (1 << 5) if @silent
|
|
22
26
|
|
|
23
27
|
result = u32_b(Constructors::MESSAGES_SEND_MESSAGE)
|
|
24
28
|
result += u32_b(flags)
|
|
@@ -26,6 +30,7 @@ module MTProto
|
|
|
26
30
|
result += serialize_reply_to if @reply_to
|
|
27
31
|
result += serialize_tl_string(@message)
|
|
28
32
|
result += u64_b(@random_id)
|
|
33
|
+
result += @reply_markup.serialize if @reply_markup
|
|
29
34
|
result
|
|
30
35
|
end
|
|
31
36
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
# A SendMessageAction — the payload of messages.setTyping. Every variant is
|
|
6
|
+
# just its own constructor id; the upload/import variants additionally carry
|
|
7
|
+
# a progress:int (0-100). One class covers them all.
|
|
8
|
+
class SendMessageAction
|
|
9
|
+
include Binary
|
|
10
|
+
|
|
11
|
+
CONSTRUCTORS = {
|
|
12
|
+
typing: 0x16bf744e,
|
|
13
|
+
cancel: 0xfd5ec8f5,
|
|
14
|
+
record_audio: 0xd52f73f7,
|
|
15
|
+
upload_audio: 0xf351d7ab,
|
|
16
|
+
record_video: 0xa187d66f,
|
|
17
|
+
upload_video: 0xe9763aec,
|
|
18
|
+
record_round: 0x88f27fbc,
|
|
19
|
+
upload_round: 0x243e1c66,
|
|
20
|
+
upload_photo: 0xd1d34a26,
|
|
21
|
+
upload_document: 0xaa0cd9e4,
|
|
22
|
+
geo_location: 0x176f8ba1,
|
|
23
|
+
choose_contact: 0x628cbc6f,
|
|
24
|
+
choose_sticker: 0xb05ac6b1,
|
|
25
|
+
game_play: 0xdd6a8f48,
|
|
26
|
+
history_import: 0xdbda9246
|
|
27
|
+
}.freeze
|
|
28
|
+
|
|
29
|
+
WITH_PROGRESS = %i[upload_audio upload_video upload_round upload_photo upload_document history_import].freeze
|
|
30
|
+
|
|
31
|
+
def self.types
|
|
32
|
+
CONSTRUCTORS.keys
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def initialize(type, progress: 0)
|
|
36
|
+
@type = type
|
|
37
|
+
@progress = progress
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def serialize
|
|
41
|
+
id = CONSTRUCTORS.fetch(@type) { raise ArgumentError, "unknown SendMessageAction: #{@type}" }
|
|
42
|
+
result = u32_b(id)
|
|
43
|
+
result += u32_b(@progress) if WITH_PROGRESS.include?(@type)
|
|
44
|
+
result
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
# messages.setBotCallbackAnswer — the bot's reaction to a press. With no
|
|
6
|
+
# message it just dismisses the button's spinner; with a message it shows a
|
|
7
|
+
# toast (alert=false) or a modal alert (alert=true).
|
|
8
|
+
class SetBotCallbackAnswer
|
|
9
|
+
include Binary
|
|
10
|
+
|
|
11
|
+
CONSTRUCTOR = 0xd58f130a
|
|
12
|
+
|
|
13
|
+
def initialize(query_id:, message: nil, alert: false, url: nil, cache_time: 0)
|
|
14
|
+
@query_id = query_id
|
|
15
|
+
@message = message
|
|
16
|
+
@alert = alert
|
|
17
|
+
@url = url
|
|
18
|
+
@cache_time = cache_time
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def serialize
|
|
22
|
+
flags = 0
|
|
23
|
+
flags |= (1 << 0) if @message
|
|
24
|
+
flags |= (1 << 1) if @alert
|
|
25
|
+
flags |= (1 << 2) if @url
|
|
26
|
+
|
|
27
|
+
result = u32_b(CONSTRUCTOR)
|
|
28
|
+
result += u32_b(flags)
|
|
29
|
+
result += u64_b(@query_id)
|
|
30
|
+
result += serialize_tl_string(@message) if @message
|
|
31
|
+
result += serialize_tl_string(@url) if @url
|
|
32
|
+
result += u32_b(@cache_time)
|
|
33
|
+
result
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def serialize_tl_string(str)
|
|
39
|
+
bytes = str.to_s.encode('UTF-8').bytes
|
|
40
|
+
length = bytes.length
|
|
41
|
+
if length <= 253
|
|
42
|
+
[length] + bytes + padding(length + 1)
|
|
43
|
+
else
|
|
44
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def padding(current_length)
|
|
49
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
50
|
+
[0] * pad_length
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'bot_command_scope'
|
|
4
|
+
|
|
5
|
+
module MTProto
|
|
6
|
+
module TL
|
|
7
|
+
class SetBotCommands
|
|
8
|
+
include Binary
|
|
9
|
+
|
|
10
|
+
CONSTRUCTOR = 0x0517165a
|
|
11
|
+
BOT_COMMAND = 0xc27ac8c7
|
|
12
|
+
|
|
13
|
+
# commands: array of { command:, description: }
|
|
14
|
+
# scope: BotCommandScope hash (see BotCommandScope); defaults to default scope.
|
|
15
|
+
def initialize(commands:, scope: { type: :default }, lang_code: '')
|
|
16
|
+
@commands = commands
|
|
17
|
+
@scope = scope
|
|
18
|
+
@lang_code = lang_code
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def serialize
|
|
22
|
+
result = u32_b(CONSTRUCTOR)
|
|
23
|
+
result += BotCommandScope.serialize(@scope)
|
|
24
|
+
result += serialize_tl_string(@lang_code)
|
|
25
|
+
result += u32_b(Constructors::VECTOR)
|
|
26
|
+
result += u32_b(@commands.size)
|
|
27
|
+
@commands.each do |cmd|
|
|
28
|
+
result += u32_b(BOT_COMMAND)
|
|
29
|
+
result += serialize_tl_string(cmd[:command])
|
|
30
|
+
result += serialize_tl_string(cmd[:description])
|
|
31
|
+
end
|
|
32
|
+
result
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def serialize_tl_string(str)
|
|
38
|
+
bytes = str.to_s.encode('UTF-8').bytes
|
|
39
|
+
length = bytes.length
|
|
40
|
+
if length <= 253
|
|
41
|
+
[length] + bytes + padding(length + 1)
|
|
42
|
+
else
|
|
43
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def padding(current_length)
|
|
48
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
49
|
+
[0] * pad_length
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module MTProto
|
|
6
|
+
module TL
|
|
7
|
+
# messages.setBotGuestChatResult#b8f106e3 query_id:long result:InputBotInlineResult
|
|
8
|
+
# = InputBotInlineMessageID
|
|
9
|
+
# How a guest-mode bot answers an updateBotGuestChatQuery: the reply text is wrapped
|
|
10
|
+
# in inputBotInlineResult(type "article") -> inputBotInlineMessageText, and the server
|
|
11
|
+
# posts that message into the guest chat. Text-only for now (no media / buttons).
|
|
12
|
+
class SetBotGuestChatResult
|
|
13
|
+
include Binary
|
|
14
|
+
|
|
15
|
+
CONSTRUCTOR = 0xb8f106e3
|
|
16
|
+
INPUT_BOT_INLINE_RESULT = 0x88bf9319 # inputBotInlineResult
|
|
17
|
+
INPUT_BOT_INLINE_MESSAGE_TEXT = 0x3dcd7a87 # inputBotInlineMessageText
|
|
18
|
+
|
|
19
|
+
def initialize(query_id:, message:, result_id: nil, result_type: 'article', result_title: nil)
|
|
20
|
+
@query_id = query_id
|
|
21
|
+
@message = message
|
|
22
|
+
@result_id = result_id || SecureRandom.hex(8)
|
|
23
|
+
@result_type = result_type
|
|
24
|
+
# The "article" result type requires a non-empty title (the server rejects an
|
|
25
|
+
# empty one with ARTICLE_TITLE_EMPTY); the actual reply shown is send_message.
|
|
26
|
+
@result_title = result_title || message_title
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def serialize
|
|
30
|
+
result = u32_b(CONSTRUCTOR)
|
|
31
|
+
result += u64_b(@query_id)
|
|
32
|
+
result += serialize_result
|
|
33
|
+
result
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
# inputBotInlineResult#88bf9319 flags:# id:string type:string
|
|
39
|
+
# title:flags.1?string description:flags.2? ... send_message:InputBotInlineMessage
|
|
40
|
+
# flags = 1<<1: id/type + the required title, then send_message.
|
|
41
|
+
def serialize_result
|
|
42
|
+
result = u32_b(INPUT_BOT_INLINE_RESULT)
|
|
43
|
+
result += u32_b(1 << 1) # title present
|
|
44
|
+
result += serialize_tl_string(@result_id)
|
|
45
|
+
result += serialize_tl_string(@result_type)
|
|
46
|
+
result += serialize_tl_string(@result_title)
|
|
47
|
+
result += serialize_send_message
|
|
48
|
+
result
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def message_title
|
|
52
|
+
title = @message.to_s.strip
|
|
53
|
+
title = 'Ответ' if title.empty?
|
|
54
|
+
title[0, 64]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true
|
|
58
|
+
# invert_media:flags.3?true message:string entities:flags.1? reply_markup:flags.2?
|
|
59
|
+
# flags = 0: a plain text message.
|
|
60
|
+
def serialize_send_message
|
|
61
|
+
result = u32_b(INPUT_BOT_INLINE_MESSAGE_TEXT)
|
|
62
|
+
result += u32_b(0)
|
|
63
|
+
result += serialize_tl_string(@message)
|
|
64
|
+
result
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def serialize_tl_string(str)
|
|
68
|
+
bytes = str.encode('UTF-8').bytes
|
|
69
|
+
length = bytes.length
|
|
70
|
+
|
|
71
|
+
if length <= 253
|
|
72
|
+
[length] + bytes + padding(length + 1)
|
|
73
|
+
else
|
|
74
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def padding(current_length)
|
|
79
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
80
|
+
[0] * pad_length
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class SetBotInfo
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
CONSTRUCTOR = 0x10cf3123
|
|
9
|
+
INPUT_USER = 0xf21158c6
|
|
10
|
+
INPUT_USER_SELF = 0xf7c1b13f
|
|
11
|
+
|
|
12
|
+
# bot: { id:, access_hash: } or { type: :self } (nil = the calling bot)
|
|
13
|
+
def initialize(bot: nil, lang_code: '', name: nil, about: nil, description: nil)
|
|
14
|
+
@bot = bot
|
|
15
|
+
@lang_code = lang_code
|
|
16
|
+
@name = name
|
|
17
|
+
@about = about
|
|
18
|
+
@description = description
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def serialize
|
|
22
|
+
flags = 0
|
|
23
|
+
flags |= (1 << 2) if @bot
|
|
24
|
+
flags |= (1 << 3) if @name
|
|
25
|
+
flags |= (1 << 0) if @about
|
|
26
|
+
flags |= (1 << 1) if @description
|
|
27
|
+
|
|
28
|
+
result = u32_b(CONSTRUCTOR)
|
|
29
|
+
result += u32_b(flags)
|
|
30
|
+
result += serialize_input_user(@bot) if @bot
|
|
31
|
+
result += serialize_tl_string(@lang_code)
|
|
32
|
+
result += serialize_tl_string(@name) if @name
|
|
33
|
+
result += serialize_tl_string(@about) if @about
|
|
34
|
+
result += serialize_tl_string(@description) if @description
|
|
35
|
+
result
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def serialize_input_user(user)
|
|
41
|
+
if user[:type] == :self
|
|
42
|
+
u32_b(INPUT_USER_SELF)
|
|
43
|
+
else
|
|
44
|
+
u32_b(INPUT_USER) + u64_b(user[:id]) + u64_b(user[:access_hash] || 0)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def serialize_tl_string(str)
|
|
49
|
+
bytes = str.to_s.encode('UTF-8').bytes
|
|
50
|
+
length = bytes.length
|
|
51
|
+
if length <= 253
|
|
52
|
+
[length] + bytes + padding(length + 1)
|
|
53
|
+
else
|
|
54
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def padding(current_length)
|
|
59
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
60
|
+
[0] * pad_length
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
# messages.setTyping — show a chat action ("typing…", "sending photo…", …)
|
|
6
|
+
# in the target peer. action is a SendMessageAction; top_msg_id targets a
|
|
7
|
+
# forum topic / thread. Returns Bool.
|
|
8
|
+
class SetTyping
|
|
9
|
+
include Binary
|
|
10
|
+
|
|
11
|
+
CONSTRUCTOR = 0x58943ee2
|
|
12
|
+
|
|
13
|
+
def initialize(peer:, action:, top_msg_id: nil)
|
|
14
|
+
@peer = peer
|
|
15
|
+
@action = action
|
|
16
|
+
@top_msg_id = top_msg_id
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def serialize
|
|
20
|
+
flags = 0
|
|
21
|
+
flags |= (1 << 0) if @top_msg_id
|
|
22
|
+
|
|
23
|
+
result = u32_b(CONSTRUCTOR)
|
|
24
|
+
result += u32_b(flags)
|
|
25
|
+
result += serialize_input_peer
|
|
26
|
+
result += u32_b(@top_msg_id) if @top_msg_id
|
|
27
|
+
result += @action.serialize
|
|
28
|
+
result
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def serialize_input_peer
|
|
34
|
+
case @peer[:type]
|
|
35
|
+
when :self
|
|
36
|
+
u32_b(Constructors::INPUT_PEER_SELF)
|
|
37
|
+
when :user
|
|
38
|
+
u32_b(Constructors::INPUT_PEER_USER) + u64_b(@peer[:id]) + u64_b(@peer[:access_hash] || 0)
|
|
39
|
+
when :chat
|
|
40
|
+
u32_b(Constructors::INPUT_PEER_CHAT) + u64_b(@peer[:id])
|
|
41
|
+
when :channel
|
|
42
|
+
u32_b(Constructors::INPUT_PEER_CHANNEL) + u64_b(@peer[:id]) + u64_b(@peer[:access_hash] || 0)
|
|
43
|
+
else
|
|
44
|
+
raise "Unknown peer type: #{@peer[:type]}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
# account.updateStatus — mark the session online or offline. offline:false
|
|
6
|
+
# is what a foreground client sends to go online (and to start receiving
|
|
7
|
+
# transient updates like updateUserTyping). Returns Bool.
|
|
8
|
+
class UpdateStatus
|
|
9
|
+
include Binary
|
|
10
|
+
|
|
11
|
+
CONSTRUCTOR = 0x6628562c
|
|
12
|
+
BOOL_TRUE = 0x997275b5
|
|
13
|
+
BOOL_FALSE = 0xbc799737
|
|
14
|
+
|
|
15
|
+
def initialize(offline:)
|
|
16
|
+
@offline = offline
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def serialize
|
|
20
|
+
u32_b(CONSTRUCTOR) + u32_b(@offline ? BOOL_TRUE : BOOL_FALSE)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|