comparison mercurial/wireprotoframing.py @ 37062:fe4c944f95bb

wireproto: use named arguments when passing around frame data Named arguments is easier to reason about compared to positional arguments. Especially when you have many positional arguments. Differential Revision: https://phab.mercurial-scm.org/D2900
author Gregory Szorc <gregory.szorc@gmail.com>
date Thu, 15 Mar 2018 16:09:58 -0700
parents 884a0c1604ad
children 39304dd63589
comparison
equal deleted inserted replaced
37061:884a0c1604ad 37062:fe4c944f95bb
111 requestid = attr.ib() 111 requestid = attr.ib()
112 typeid = attr.ib() 112 typeid = attr.ib()
113 flags = attr.ib() 113 flags = attr.ib()
114 payload = attr.ib() 114 payload = attr.ib()
115 115
116 def makeframe(requestid, frametype, frameflags, payload): 116 def makeframe(requestid, typeid, flags, payload):
117 """Assemble a frame into a byte array.""" 117 """Assemble a frame into a byte array."""
118 # TODO assert size of payload. 118 # TODO assert size of payload.
119 frame = bytearray(FRAME_HEADER_SIZE + len(payload)) 119 frame = bytearray(FRAME_HEADER_SIZE + len(payload))
120 120
121 # 24 bits length 121 # 24 bits length
124 # 4 bits flags 124 # 4 bits flags
125 125
126 l = struct.pack(r'<I', len(payload)) 126 l = struct.pack(r'<I', len(payload))
127 frame[0:3] = l[0:3] 127 frame[0:3] = l[0:3]
128 struct.pack_into(r'<H', frame, 3, requestid) 128 struct.pack_into(r'<H', frame, 3, requestid)
129 frame[5] = (frametype << 4) | frameflags 129 frame[5] = (typeid << 4) | flags
130 frame[6:] = payload 130 frame[6:] = payload
131 131
132 return frame 132 return frame
133 133
134 def makeframefromhumanstring(s): 134 def makeframefromhumanstring(s):
164 else: 164 else:
165 finalflags |= int(flag) 165 finalflags |= int(flag)
166 166
167 payload = util.unescapestr(payload) 167 payload = util.unescapestr(payload)
168 168
169 return makeframe(requestid, frametype, finalflags, payload) 169 return makeframe(requestid=requestid, typeid=frametype,
170 flags=finalflags, payload=payload)
170 171
171 def parseheader(data): 172 def parseheader(data):
172 """Parse a unified framing protocol frame header from a buffer. 173 """Parse a unified framing protocol frame header from a buffer.
173 174
174 The header is expected to be in the buffer at offset 0 and the 175 The header is expected to be in the buffer at offset 0 and the
227 flags |= FLAG_COMMAND_NAME_HAVE_DATA 228 flags |= FLAG_COMMAND_NAME_HAVE_DATA
228 229
229 if not flags: 230 if not flags:
230 flags |= FLAG_COMMAND_NAME_EOS 231 flags |= FLAG_COMMAND_NAME_EOS
231 232
232 yield makeframe(requestid, FRAME_TYPE_COMMAND_NAME, flags, cmd) 233 yield makeframe(requestid=requestid, typeid=FRAME_TYPE_COMMAND_NAME,
234 flags=flags, payload=cmd)
233 235
234 for i, k in enumerate(sorted(args)): 236 for i, k in enumerate(sorted(args)):
235 v = args[k] 237 v = args[k]
236 last = i == len(args) - 1 238 last = i == len(args) - 1
237 239
243 payload[offset:offset + len(k)] = k 245 payload[offset:offset + len(k)] = k
244 offset += len(k) 246 offset += len(k)
245 payload[offset:offset + len(v)] = v 247 payload[offset:offset + len(v)] = v
246 248
247 flags = FLAG_COMMAND_ARGUMENT_EOA if last else 0 249 flags = FLAG_COMMAND_ARGUMENT_EOA if last else 0
248 yield makeframe(requestid, FRAME_TYPE_COMMAND_ARGUMENT, flags, payload) 250 yield makeframe(requestid=requestid,
251 typeid=FRAME_TYPE_COMMAND_ARGUMENT,
252 flags=flags,
253 payload=payload)
249 254
250 if datafh: 255 if datafh:
251 while True: 256 while True:
252 data = datafh.read(DEFAULT_MAX_FRAME_SIZE) 257 data = datafh.read(DEFAULT_MAX_FRAME_SIZE)
253 258
257 else: 262 else:
258 flags = FLAG_COMMAND_DATA_EOS 263 flags = FLAG_COMMAND_DATA_EOS
259 assert datafh.read(1) == b'' 264 assert datafh.read(1) == b''
260 done = True 265 done = True
261 266
262 yield makeframe(requestid, FRAME_TYPE_COMMAND_DATA, flags, data) 267 yield makeframe(requestid=requestid,
268 typeid=FRAME_TYPE_COMMAND_DATA,
269 flags=flags,
270 payload=data)
263 271
264 if done: 272 if done:
265 break 273 break
266 274
267 def createbytesresponseframesfrombytes(requestid, data, 275 def createbytesresponseframesfrombytes(requestid, data,
271 Returns a generator of bytearrays. 279 Returns a generator of bytearrays.
272 """ 280 """
273 281
274 # Simple case of a single frame. 282 # Simple case of a single frame.
275 if len(data) <= maxframesize: 283 if len(data) <= maxframesize:
276 yield makeframe(requestid, FRAME_TYPE_BYTES_RESPONSE, 284 yield makeframe(requestid=requestid,
277 FLAG_BYTES_RESPONSE_EOS, data) 285 typeid=FRAME_TYPE_BYTES_RESPONSE,
286 flags=FLAG_BYTES_RESPONSE_EOS,
287 payload=data)
278 return 288 return
279 289
280 offset = 0 290 offset = 0
281 while True: 291 while True:
282 chunk = data[offset:offset + maxframesize] 292 chunk = data[offset:offset + maxframesize]
286 if done: 296 if done:
287 flags = FLAG_BYTES_RESPONSE_EOS 297 flags = FLAG_BYTES_RESPONSE_EOS
288 else: 298 else:
289 flags = FLAG_BYTES_RESPONSE_CONTINUATION 299 flags = FLAG_BYTES_RESPONSE_CONTINUATION
290 300
291 yield makeframe(requestid, FRAME_TYPE_BYTES_RESPONSE, flags, chunk) 301 yield makeframe(requestid=requestid,
302 typeid=FRAME_TYPE_BYTES_RESPONSE,
303 flags=flags,
304 payload=chunk)
292 305
293 if done: 306 if done:
294 break 307 break
295 308
296 def createerrorframe(requestid, msg, protocol=False, application=False): 309 def createerrorframe(requestid, msg, protocol=False, application=False):
301 if protocol: 314 if protocol:
302 flags |= FLAG_ERROR_RESPONSE_PROTOCOL 315 flags |= FLAG_ERROR_RESPONSE_PROTOCOL
303 if application: 316 if application:
304 flags |= FLAG_ERROR_RESPONSE_APPLICATION 317 flags |= FLAG_ERROR_RESPONSE_APPLICATION
305 318
306 yield makeframe(requestid, FRAME_TYPE_ERROR_RESPONSE, flags, msg) 319 yield makeframe(requestid=requestid,
320 typeid=FRAME_TYPE_ERROR_RESPONSE,
321 flags=flags,
322 payload=msg)
307 323
308 def createtextoutputframe(requestid, atoms): 324 def createtextoutputframe(requestid, atoms):
309 """Create a text output frame to render text to people. 325 """Create a text output frame to render text to people.
310 326
311 ``atoms`` is a 3-tuple of (formatting string, args, labels). 327 ``atoms`` is a 3-tuple of (formatting string, args, labels).
369 bytesleft -= len(atom) 385 bytesleft -= len(atom)
370 386
371 if bytesleft < 0: 387 if bytesleft < 0:
372 raise ValueError('cannot encode data in a single frame') 388 raise ValueError('cannot encode data in a single frame')
373 389
374 yield makeframe(requestid, FRAME_TYPE_TEXT_OUTPUT, 0, b''.join(atomchunks)) 390 yield makeframe(requestid=requestid,
391 typeid=FRAME_TYPE_TEXT_OUTPUT,
392 flags=0,
393 payload=b''.join(atomchunks))
375 394
376 class serverreactor(object): 395 class serverreactor(object):
377 """Holds state of a server handling frame-based protocol requests. 396 """Holds state of a server handling frame-based protocol requests.
378 397
379 This class is the "brain" of the unified frame-based protocol server 398 This class is the "brain" of the unified frame-based protocol server