22import socket
33import stat
44import json
5+ import asyncio
6+ import time
57
68def read_one_frame_from_uds (socket_path , header_size_hint = None , timeout_s = 5.0 ):
79 """
810 Reads exactly one frame from the snapshot.c client-facing UDS format:
9- [2-byte big-endian module_id]
10- [JSON header ending with b'\\ n\\ n'] (if header_size_hint is provided, readexactly that many)
11- ['*']
12- [binary image bytes], where size is inferred by the consumer.
11+ [2-byte big-endian module_id]
12+ [JSON header ending with b'\\ n\\ n'] (if header_size_hint is provided, readexactly that many)
13+ ['*']
14+ [binary image bytes], where size is inferred by the consumer.
1315 Returns (module_id, header_dict, raw_image_bytes)
1416 """
1517 # Sanity check
@@ -38,6 +40,7 @@ def read_one_frame_from_uds(socket_path, header_size_hint=None, timeout_s=5.0):
3840 # fallback: find the terminator
3941 extra = _recv_until (sock , b"\n \n " )
4042 header_bytes += extra
43+
4144 header_json = header_bytes [:- 2 ].decode ("utf-8" )
4245 header = json .loads (header_json )
4346
@@ -47,14 +50,33 @@ def read_one_frame_from_uds(socket_path, header_size_hint=None, timeout_s=5.0):
4750 if star != b"*" :
4851 raise RuntimeError (f"Expected '*' before image payload, got { star !r} " )
4952
50- # Without the dp’ s exact bytes_per_image, we don’ t know total bytes.
53+ # Without the dp' s exact bytes_per_image, we don' t know total bytes.
5154 # For tests, read a safe upper bound then return what we got in one recv.
5255 # A robust client would know bytes_per_image. For CI, read a max buffer.
5356 img = _recv_at_most (sock , 4096 ) # enough for ph256/img16 frame sizes in CI
57+
5458 return module_id , header , img
59+
5560 finally :
5661 sock .close ()
5762
63+ def read_one_frame_with_retry (socket_path , retries = 5 , base_timeout = 8.0 ):
64+ """
65+ Read one frame with retries and exponential backoff for robust testing.
66+ """
67+ for attempt in range (retries ):
68+ timeout = base_timeout * (1.5 ** attempt ) # Exponential backoff
69+ try :
70+ result = read_one_frame_from_uds (socket_path , timeout_s = timeout )
71+ print (f"Successfully read frame on attempt { attempt + 1 } " )
72+ return result
73+ except Exception as e :
74+ print (f"Attempt { attempt + 1 } failed: { e } " )
75+ if attempt < retries - 1 :
76+ time .sleep (0.5 * (attempt + 1 )) # Progressive delay
77+
78+ raise RuntimeError (f"Failed to read frame after { retries } attempts" )
79+
5880def _recv_exact (sock , n ):
5981 buf = bytearray ()
6082 while len (buf ) < n :
0 commit comments