Class: MTProto::Type::RPC::Updates::Difference
- Inherits:
-
Object
- Object
- MTProto::Type::RPC::Updates::Difference
- Defined in:
- lib/mtproto/type/rpc/updates/difference.rb
Constant Summary collapse
- CONSTRUCTOR_DIFFERENCE =
0x00f49ca0- CONSTRUCTOR_DIFFERENCE_EMPTY =
0x5d75a138- CONSTRUCTOR_DIFFERENCE_SLICE =
0xa8fb1981- CONSTRUCTOR_DIFFERENCE_TOO_LONG =
0x4afe8f6d- CONSTRUCTOR_UPDATE_SHORT =
Updates constructors (can be returned instead of Difference)
0x78d4dec1- CONSTRUCTOR_UPDATES =
0x74ae4240- CONSTRUCTOR_UPDATE_SHORT_MESSAGE =
0x313bc7f8- CONSTRUCTOR_UPDATE_SHORT_CHAT_MESSAGE =
0x402d5dbb- CONSTRUCTOR_UPDATE_SHORT_SENT_MESSAGE =
0x11f1331c- VECTOR_CONSTRUCTOR =
0x1cb5c415- MESSAGE_CONSTRUCTOR =
0x452c0e65- MESSAGE_EMPTY_CONSTRUCTOR =
0x83e5de54
Class Method Summary collapse
- .parse(response) ⇒ Object
- .parse_message(response, offset) ⇒ Object
- .parse_messages_vector(response, offset) ⇒ Object
- .parse_user(response, offset) ⇒ Object
- .parse_users_vector(response, offset) ⇒ Object
- .skip_vector(response, offset) ⇒ Object
Class Method Details
.parse(response) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 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 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/mtproto/type/rpc/updates/difference.rb', line 27 def self.parse(response) offset = 0 constructor = response[offset, 4].unpack1('L<') offset += 4 if constructor == Type::GzipPacked::CONSTRUCTOR response = Type::GzipPacked.unpack(response) constructor = response[0, 4].unpack1('L<') offset = 4 end if constructor == Type::RpcError::CONSTRUCTOR error = Type::RpcError.deserialize(response) raise MTProto::RpcError.new(error.error_code, error.) end case constructor when CONSTRUCTOR_DIFFERENCE_EMPTY # updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; date = response[offset, 4].unpack1('L<') offset += 4 seq = response[offset, 4].unpack1('L<') { type: :empty, date: date, seq: seq, new_messages: [], state: nil } when CONSTRUCTOR_DIFFERENCE, CONSTRUCTOR_DIFFERENCE_SLICE # updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference; # updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> intermediate_state:updates.State = updates.Difference; # Parse new_messages vector , offset = (response, offset) # Skip new_encrypted_messages vector offset = skip_vector(response, offset) # Skip other_updates vector offset = skip_vector(response, offset) # Skip chats vector offset = skip_vector(response, offset) # Parse users vector users, offset = parse_users_vector(response, offset) { type: constructor == CONSTRUCTOR_DIFFERENCE ? :difference : :slice, new_messages: , users: users, state: nil # Would need to parse state } when CONSTRUCTOR_DIFFERENCE_TOO_LONG # updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; pts = response[offset, 4].unpack1('L<') { type: :too_long, pts: pts, new_messages: [], state: nil } when CONSTRUCTOR_UPDATE_SHORT_MESSAGE # updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector<MessageEntity> ttl_period:flags.25?int = Updates; flags = response[offset, 4].unpack1('L<') offset += 4 id = response[offset, 4].unpack1('L<') offset += 4 user_id = response[offset, 8].unpack1('Q<') offset += 8 # Parse message string msg_len = response[offset].unpack1('C') offset += 1 = response[offset, msg_len].force_encoding('UTF-8') offset += msg_len padding = (4 - ((1 + msg_len) % 4)) % 4 offset += padding pts = response[offset, 4].unpack1('L<') offset += 4 pts_count = response[offset, 4].unpack1('L<') offset += 4 date = response[offset, 4].unpack1('L<') offset += 4 # Return with the extracted message { type: :short_message, new_messages: [{ id: id, user_id: user_id, date: date, message: , flags: flags }], state: { pts: pts, pts_count: pts_count } } when CONSTRUCTOR_UPDATE_SHORT, CONSTRUCTOR_UPDATES, CONSTRUCTOR_UPDATE_SHORT_CHAT_MESSAGE, CONSTRUCTOR_UPDATE_SHORT_SENT_MESSAGE # Sometimes getDifference returns Updates instead of Difference # This means there are no new differences, treat as empty { type: :empty, date: Time.now.to_i, seq: 0, new_messages: [], state: nil } else # Unknown constructor - likely an Updates variant we don't handle yet # Treat as empty to avoid breaking the polling loop warn "Warning: Unknown Difference/Updates constructor: 0x#{constructor.to_s(16)}, treating as empty" { type: :empty, date: Time.now.to_i, seq: 0, new_messages: [], state: nil } end end |
.parse_message(response, offset) ⇒ Object
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/mtproto/type/rpc/updates/difference.rb', line 185 def self.(response, offset) msg_constructor = response[offset, 4].unpack1('L<') offset += 4 return [nil, offset] if msg_constructor == MESSAGE_EMPTY_CONSTRUCTOR return [nil, offset] unless msg_constructor == MESSAGE_CONSTRUCTOR # message#452c0e65 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true offline:flags.30?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags.31?long = Message; flags = response[offset, 4].unpack1('L<') offset += 4 # For simplicity, we'll just extract id, date, and message text # A full implementation would parse all fields based on flags id = response[offset, 4].unpack1('L<') offset += 4 # Skip from_id if present (flags.8) if (flags & (1 << 8)) != 0 # Skip Peer object (constructor + id, could be user/chat/channel) offset += 4 # peer constructor offset += 8 # peer id (long for user, int for others, but let's assume worst case) end # Skip from_boosts_applied if present (flags.29) offset += 4 if (flags & (1 << 29)) != 0 # peer_id:Peer (always present) - skip it offset += 4 # peer constructor offset += 8 # peer id # Skip fwd_from if present (flags.2) # This is complex, so we'll just skip ahead assuming it's not there for now # Skip via_bot_id if present (flags.11) offset += 8 if (flags & (1 << 11)) != 0 # Skip reply_to if present (flags.3) # Complex object, skip for now # date:int (always present) date = response[offset, 4].unpack1('L<') offset += 4 # message:string (always present) msg_len = response[offset].unpack1('C') offset += 1 = response[offset, msg_len].force_encoding('UTF-8') offset += msg_len padding = (4 - ((1 + msg_len) % 4)) % 4 offset += padding # Return simplified message [{ id: id, date: date, message: , flags: flags }, offset] rescue StandardError => e # If parsing fails, skip this message [nil, offset] end |
.parse_messages_vector(response, offset) ⇒ Object
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/mtproto/type/rpc/updates/difference.rb', line 166 def self.(response, offset) # Check for Vector constructor vector_constructor = response[offset, 4].unpack1('L<') offset += 4 return [[], offset] unless vector_constructor == VECTOR_CONSTRUCTOR count = response[offset, 4].unpack1('L<') offset += 4 = [] count.times do , offset = (response, offset) << if end [, offset] end |
.parse_user(response, offset) ⇒ Object
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/mtproto/type/rpc/updates/difference.rb', line 296 def self.parse_user(response, offset) user_constructor = response[offset, 4].unpack1('L<') offset += 4 # user#20b1422 flags:# flags2:# id:long access_hash:flags.0?long ... return [nil, offset] unless user_constructor == 0x20b1422 flags = response[offset, 4].unpack1('L<') offset += 4 flags2 = response[offset, 4].unpack1('L<') offset += 4 # id:long (always present) user_id = response[offset, 8].unpack1('Q<') offset += 8 # access_hash:flags.0?long (conditional) access_hash = nil if (flags & (1 << 0)) != 0 access_hash = response[offset, 8].unpack1('Q<') offset += 8 end # We have what we need, skip the rest [{ id: user_id, access_hash: access_hash }, offset] rescue StandardError => e [nil, offset] end |
.parse_users_vector(response, offset) ⇒ Object
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/mtproto/type/rpc/updates/difference.rb', line 277 def self.parse_users_vector(response, offset) # Check for Vector constructor vector_constructor = response[offset, 4].unpack1('L<') offset += 4 return [[], offset] unless vector_constructor == VECTOR_CONSTRUCTOR count = response[offset, 4].unpack1('L<') offset += 4 users = [] count.times do user, offset = parse_user(response, offset) users << user if user end [users, offset] end |
.skip_vector(response, offset) ⇒ Object
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/mtproto/type/rpc/updates/difference.rb', line 251 def self.skip_vector(response, offset) # Read vector constructor vector_constructor = response[offset, 4].unpack1('L<') offset += 4 return offset unless vector_constructor == VECTOR_CONSTRUCTOR # Read count count = response[offset, 4].unpack1('L<') offset += 4 # Skip each element - we can't know the size, so return offset as-is # This is a limitation - proper skipping would require parsing each element # For now, just read the constructor of each element and skip based on known patterns count.times do constructor = response[offset, 4].unpack1('L<') offset += 4 # This is a simplified skip - real implementation would need to parse each type # For now, skip a reasonable amount (most TL objects are small) # This is fragile but works for common cases end offset end |