2525 RawCopy ,
2626 Struct ,
2727 bytestringtype ,
28+ stream_seek ,
29+ stream_tell ,
2830)
2931from Crypto .Cipher import AES
3032from Crypto .Util .Padding import pad , unpad
@@ -223,43 +225,51 @@ def _parse(self, stream, context, path):
223225 return hash1
224226
225227
226- class OptionalPrefix ( Construct ):
228+ class PrefixedStruct ( Struct ):
227229 def _parse (self , stream , context , path ):
228230 subcon1 = Peek (Optional (Const (b"1.0" )))
229231 peek_version = subcon1 .parse_stream (stream , ** context )
230232 if peek_version is None :
231233 subcon2 = Bytes (4 )
232- return subcon2 .parse_stream (stream , ** context )
233- return b""
234+ subcon2 .parse_stream (stream , ** context )
235+ return super (). _parse ( stream , context , path )
234236
235237 def _build (self , obj , stream , context , path ):
236- if obj is not None :
237- subcon1 = Bytes (4 )
238- subcon1 .build_stream (obj , stream , ** context )
238+ prefixed = context .search ("prefixed" )
239+ if not prefixed :
240+ return super ()._build (obj , stream , context , path )
241+ offset = stream_tell (stream , path )
242+ stream_seek (stream , offset + 4 , 0 , path )
243+ super ()._build (obj , stream , context , path )
244+ new_offset = stream_tell (stream , path )
245+ subcon1 = Bytes (4 )
246+ stream_seek (stream , offset , 0 , path )
247+ subcon1 .build_stream (new_offset - offset - subcon1 .sizeof (** context ), stream , ** context )
248+ stream_seek (stream , new_offset + 4 , 0 , path )
239249 return obj
240250
241251
252+ _Message = RawCopy (
253+ Struct (
254+ "version" / Const (b"1.0" ),
255+ "seq" / Int32ub ,
256+ "random" / Int32ub ,
257+ "timestamp" / Int32ub ,
258+ "protocol" / Int16ub ,
259+ "payload"
260+ / EncryptionAdapter (
261+ lambda ctx : Utils .md5 (
262+ Utils .encode_timestamp (ctx .timestamp ) + Utils .ensure_bytes (ctx .search ("local_key" )) + SALT
263+ ),
264+ ),
265+ )
266+ )
267+
242268_Messages = Struct (
243269 "messages"
244270 / GreedyRange (
245- Struct (
246- "prefix" / OptionalPrefix (),
247- "message"
248- / RawCopy (
249- Struct (
250- "version" / Const (b"1.0" ),
251- "seq" / Int32ub ,
252- "random" / Int32ub ,
253- "timestamp" / Int32ub ,
254- "protocol" / Int16ub ,
255- "payload"
256- / EncryptionAdapter (
257- lambda ctx : Utils .md5 (
258- Utils .encode_timestamp (ctx .timestamp ) + Utils .ensure_bytes (ctx .search ("local_key" )) + SALT
259- ),
260- ),
261- )
262- ),
271+ PrefixedStruct (
272+ "message" / _Message ,
263273 "checksum" / OptionalChecksum (Optional (Int32ub ), Utils .crc , lambda ctx : ctx .message .data ),
264274 )
265275 ),
@@ -294,7 +304,6 @@ def parse(self, data: bytes, local_key: str | None = None) -> tuple[list[Roboroc
294304 for message in parsed_messages :
295305 messages .append (
296306 RoborockMessage (
297- prefix = message .get ("prefix" ),
298307 version = message .message .value .version ,
299308 seq = message .message .value .seq ,
300309 random = message .message .value .get ("random" ),
@@ -306,14 +315,15 @@ def parse(self, data: bytes, local_key: str | None = None) -> tuple[list[Roboroc
306315 remaining = parsed .get ("remaining" ) or b""
307316 return messages , remaining
308317
309- def build (self , roborock_messages : list [RoborockMessage ] | RoborockMessage , local_key : str ) -> bytes :
318+ def build (
319+ self , roborock_messages : list [RoborockMessage ] | RoborockMessage , local_key : str , prefixed : bool = True
320+ ) -> bytes :
310321 if isinstance (roborock_messages , RoborockMessage ):
311322 roborock_messages = [roborock_messages ]
312323 messages = []
313324 for roborock_message in roborock_messages :
314325 messages .append (
315326 {
316- "prefix" : roborock_message .prefix ,
317327 "message" : {
318328 "value" : {
319329 "version" : roborock_message .version ,
@@ -326,7 +336,7 @@ def build(self, roborock_messages: list[RoborockMessage] | RoborockMessage, loca
326336 },
327337 }
328338 )
329- return self .con .build ({"messages" : [message for message in messages ]}, local_key = local_key )
339+ return self .con .build ({"messages" : [message for message in messages ]}, local_key = local_key , prefixed = prefixed )
330340
331341
332342MessageParser : _Parser = _Parser (_Messages , True )
0 commit comments