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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/data/tl-schema.json +47158 -42684
  3. data/lib/mtproto/auth_key_generator.rb +2 -2
  4. data/lib/mtproto/client/api/export_authorization.rb +17 -0
  5. data/lib/mtproto/client/api/import_authorization.rb +23 -0
  6. data/lib/mtproto/client/api.rb +2 -0
  7. data/lib/mtproto/client/rpc.rb +33 -0
  8. data/lib/mtproto/client.rb +54 -1
  9. data/lib/mtproto/file_downloader.rb +122 -0
  10. data/lib/mtproto/tl/constructor_names.rb +324 -109
  11. data/lib/mtproto/tl/constructors.rb +16 -8
  12. data/lib/mtproto/tl/objects/bot_command_scope.rb +81 -0
  13. data/lib/mtproto/tl/objects/channels_join_channel.rb +1 -1
  14. data/lib/mtproto/tl/objects/channels_update_username.rb +42 -0
  15. data/lib/mtproto/tl/objects/contacts.rb +1 -1
  16. data/lib/mtproto/tl/objects/create_bot.rb +54 -0
  17. data/lib/mtproto/tl/objects/dialogs.rb +25 -10
  18. data/lib/mtproto/tl/objects/edit_access_settings.rb +46 -0
  19. data/lib/mtproto/tl/objects/export_authorization.rb +17 -0
  20. data/lib/mtproto/tl/objects/export_bot_token.rb +32 -0
  21. data/lib/mtproto/tl/objects/exported_authorization.rb +32 -0
  22. data/lib/mtproto/tl/objects/exported_bot_token.rb +27 -0
  23. data/lib/mtproto/tl/objects/forward_messages.rb +12 -3
  24. data/lib/mtproto/tl/objects/get_access_settings.rb +28 -0
  25. data/lib/mtproto/tl/objects/get_bot_callback_answer.rb +67 -0
  26. data/lib/mtproto/tl/objects/get_bot_commands.rb +46 -0
  27. data/lib/mtproto/tl/objects/get_file.rb +10 -2
  28. data/lib/mtproto/tl/objects/import_authorization.rb +38 -0
  29. data/lib/mtproto/tl/objects/input_keyboard_button_request_peer.rb +54 -0
  30. data/lib/mtproto/tl/objects/keyboard_button_callback.rb +50 -0
  31. data/lib/mtproto/tl/objects/message.rb +97 -21
  32. data/lib/mtproto/tl/objects/messages.rb +7 -74
  33. data/lib/mtproto/tl/objects/messages_get_messages.rb +26 -0
  34. data/lib/mtproto/tl/objects/reply_inline_markup.rb +30 -0
  35. data/lib/mtproto/tl/objects/reply_keyboard_markup.rb +35 -0
  36. data/lib/mtproto/tl/objects/request_peer_type_create_bot.rb +47 -0
  37. data/lib/mtproto/tl/objects/reset_bot_commands.rb +45 -0
  38. data/lib/mtproto/tl/objects/send_bot_requested_peer.rb +51 -0
  39. data/lib/mtproto/tl/objects/send_media.rb +87 -4
  40. data/lib/mtproto/tl/objects/send_message.rb +7 -2
  41. data/lib/mtproto/tl/objects/send_message_action.rb +48 -0
  42. data/lib/mtproto/tl/objects/set_bot_callback_answer.rb +54 -0
  43. data/lib/mtproto/tl/objects/set_bot_commands.rb +53 -0
  44. data/lib/mtproto/tl/objects/set_bot_guest_chat_result.rb +84 -0
  45. data/lib/mtproto/tl/objects/set_bot_info.rb +64 -0
  46. data/lib/mtproto/tl/objects/set_typing.rb +49 -0
  47. data/lib/mtproto/tl/objects/update_status.rb +24 -0
  48. data/lib/mtproto/tl/objects/updates.rb +117 -0
  49. data/lib/mtproto/tl/objects/updates_difference.rb +45 -69
  50. data/lib/mtproto/tl/objects/upload_profile_photo.rb +65 -0
  51. data/lib/mtproto/tl/reader.rb +188 -0
  52. data/lib/mtproto/transport/abridged_packet_codec.rb +5 -1
  53. data/lib/mtproto/unencrypted_message.rb +39 -0
  54. data/lib/mtproto/version.rb +1 -1
  55. data/lib/mtproto.rb +4 -1
  56. data/scripts/gen_constructor_names.rb +72 -0
  57. data/scripts/tl_to_json.rb +72 -0
  58. data/scripts/verify_ids.rb +33 -0
  59. metadata +38 -2
  60. 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
- def initialize(peer:, media:, message: '', random_id: nil)
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(0) # flags
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
- bytes = str.encode('UTF-8').bytes
70
- length = bytes.length
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 = 0x869fbe10
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