Module: MTProto::TL::MessageEntities
- Extended by:
- Binary
- Defined in:
- lib/mtproto/tl/message_entity.rb
Overview
Codec for Vector<MessageEntity> — the formatting-span list carried by
messages.sendMessage/editMessage (entities, flags.3) and parsed back out of an
inbound message. serialize builds the wire byte array from [MessageEntity];
parse reads it back. Layouts follow the layer-227 schema. The only input vs
output split is the text-mention: sending uses inputMessageEntityMentionName
(an InputUser), a received one is messageEntityMentionName (a bare user_id).
Constant Summary collapse
- VECTOR =
0x1cb5c415- INPUT_USER =
0xf21158c6- INPUT_USER_SELF =
0xf7c1b13f- INPUT_MESSAGE_ENTITY_MENTION_NAME =
0x208e68c9- TYPE_TO_CTOR =
type -> constructor id for the entities that are identical on input/output.
{ unknown: 0xbb92ba95, mention: 0xfa04579d, hashtag: 0x6f635b0d, bot_command: 0x6cef8ac7, url: 0x6ed02538, email: 0x64e475c2, bold: 0xbd610bc9, italic: 0x826f8b60, code: 0x28a20571, pre: 0x73924be0, text_url: 0x76a6d327, mention_name: 0xdc7b1140, phone: 0x9b69e34b, cashtag: 0x4c4e743f, underline: 0x9c4e7e8b, strike: 0xbf0693d4, bank_card: 0x761e6af4, spoiler: 0x32ca960f, custom_emoji: 0xc8cf05f8, blockquote: 0xf1ccaaac }.freeze
- CTOR_TO_TYPE =
TYPE_TO_CTOR.invert.freeze
Class Method Summary collapse
-
.parse(data, offset) ⇒ Object
Wire byte array + new offset for one
Vector<MessageEntity>atoffset; returns [[MessageEntity], new_offset]. - .parse_entity(data, offset) ⇒ Object
-
.serialize(entities) ⇒ Object
[MessageEntity] -> wire byte array for
Vector<MessageEntity>. -
.serialize_entity(entity) ⇒ Object
Wire byte array for one entity, dispatched on its type.
-
.serialize_mention_name(entity) ⇒ Object
inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser.
-
.tl_string(str) ⇒ Object
TL
stringserializer (byte array): a length-prefixed, 4-byte-padded blob.
Methods included from Binary
Class Method Details
.parse(data, offset) ⇒ Object
Wire byte array + new offset for one Vector<MessageEntity> at offset;
returns [[MessageEntity], new_offset]. An entity constructor we don't model is
stepped over via the schema sizer so the walk stays aligned (and dropped).
84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/mtproto/tl/message_entity.rb', line 84 def parse(data, offset) return [[], offset] unless data[offset, 4].unpack1('L<') == VECTOR io = offset + 4 count = data[io, 4].unpack1('L<') io += 4 entities = [] count.times do entity, io = parse_entity(data, io) entities << entity if entity end [entities, io] end |
.parse_entity(data, offset) ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/mtproto/tl/message_entity.rb', line 98 def parse_entity(data, offset) ctor = data[offset, 4].unpack1('L<') type = CTOR_TO_TYPE[ctor] return [nil, Reader.schema.skip(data, offset)] if type.nil? io = offset + 4 collapsed = nil if type == :blockquote collapsed = data[io, 4].unpack1('L<').anybits?(1 << 0) io += 4 end ent_offset = data[io, 4].unpack1('l<') ent_length = data[io + 4, 4].unpack1('l<') io += 8 extra = {} case type when :text_url extra[:url], io = Reader.read_tl_string(data, io) when :pre extra[:language], io = Reader.read_tl_string(data, io) when :mention_name extra[:user_id] = data[io, 8].unpack1('q<') io += 8 when :custom_emoji extra[:document_id] = data[io, 8].unpack1('q<') io += 8 end [MessageEntity.new(type: type, offset: ent_offset, length: ent_length, collapsed: collapsed, **extra), io] end |
.serialize(entities) ⇒ Object
[MessageEntity] -> wire byte array for Vector<MessageEntity>.
55 56 57 58 59 |
# File 'lib/mtproto/tl/message_entity.rb', line 55 def serialize(entities) out = u32_b(VECTOR) + u32_b(entities.length) entities.each { |e| out += serialize_entity(e) } out end |
.serialize_entity(entity) ⇒ Object
Wire byte array for one entity, dispatched on its type. Sending a text-mention needs an InputUser: an explicit access_hash, or 0 for a user the DC already knows (e.g. a mutual contact); a wrong hash is rejected by the server.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/mtproto/tl/message_entity.rb', line 64 def serialize_entity(entity) return serialize_mention_name(entity) if entity.type == :mention_name ctor = TYPE_TO_CTOR.fetch(entity.type) do raise ArgumentError, "unknown entity type: #{entity.type.inspect}" end bytes = u32_b(ctor) bytes += u32_b(entity.collapsed ? 1 : 0) if entity.type == :blockquote # flags.0 collapsed bytes += u32_b(entity.offset) + u32_b(entity.length) case entity.type when :text_url then bytes += tl_string(entity.url.to_s) when :pre then bytes += tl_string(entity.language.to_s) when :custom_emoji then bytes += u64_b(entity.document_id) end bytes end |
.serialize_mention_name(entity) ⇒ Object
inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser.
129 130 131 132 133 134 135 136 137 |
# File 'lib/mtproto/tl/message_entity.rb', line 129 def serialize_mention_name(entity) input_user = if entity.user_id.nil? u32_b(INPUT_USER_SELF) else u32_b(INPUT_USER) + u64_b(entity.user_id) + u64_b(entity.access_hash || 0) end u32_b(INPUT_MESSAGE_ENTITY_MENTION_NAME) + u32_b(entity.offset) + u32_b(entity.length) + input_user end |
.tl_string(str) ⇒ Object
TL string serializer (byte array): a length-prefixed, 4-byte-padded blob.
Mirrors SendMessage#serialize_tl_string; kept local so the codec stands alone.
141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/mtproto/tl/message_entity.rb', line 141 def tl_string(str) bytes = str.to_s.dup.force_encoding('BINARY').bytes length = bytes.length if length <= 253 padding = (4 - ((length + 1) % 4)) % 4 [length] + bytes + ([0] * padding) else padding = (4 - ((length + 4) % 4)) % 4 [254] + u32_b(length)[0, 3] + bytes + ([0] * padding) end end |