changeset 52699 | 068398a8c9cb |
parent 52698 | 1a612f9ec2c4 |
52698:1a612f9ec2c4 | 52699:068398a8c9cb |
---|---|
39 from .utils import ( |
39 from .utils import ( |
40 cborutil, |
40 cborutil, |
41 stringutil, |
41 stringutil, |
42 ) |
42 ) |
43 |
43 |
44 if typing.TYPE_CHECKING: |
|
45 from typing import ( |
|
46 Iterator, |
|
47 ) |
|
48 |
|
49 HandleSendFramesReturnT = tuple[bytes, dict[bytes, Iterator[bytearray]]] |
|
50 |
|
44 FRAME_HEADER_SIZE = 8 |
51 FRAME_HEADER_SIZE = 8 |
45 DEFAULT_MAX_FRAME_SIZE = 32768 |
52 DEFAULT_MAX_FRAME_SIZE = 32768 |
46 |
53 |
47 STREAM_FLAG_BEGIN_STREAM = 0x01 |
54 STREAM_FLAG_BEGIN_STREAM = 0x01 |
48 STREAM_FLAG_END_STREAM = 0x02 |
55 STREAM_FLAG_END_STREAM = 0x02 |
49 STREAM_FLAG_ENCODING_APPLIED = 0x04 |
56 STREAM_FLAG_ENCODING_APPLIED = 0x04 |
50 |
57 |
51 STREAM_FLAGS = { |
58 STREAM_FLAGS: dict[bytes, int] = { |
52 b'stream-begin': STREAM_FLAG_BEGIN_STREAM, |
59 b'stream-begin': STREAM_FLAG_BEGIN_STREAM, |
53 b'stream-end': STREAM_FLAG_END_STREAM, |
60 b'stream-end': STREAM_FLAG_END_STREAM, |
54 b'encoded': STREAM_FLAG_ENCODING_APPLIED, |
61 b'encoded': STREAM_FLAG_ENCODING_APPLIED, |
55 } |
62 } |
56 |
63 |
61 FRAME_TYPE_TEXT_OUTPUT = 0x06 |
68 FRAME_TYPE_TEXT_OUTPUT = 0x06 |
62 FRAME_TYPE_PROGRESS = 0x07 |
69 FRAME_TYPE_PROGRESS = 0x07 |
63 FRAME_TYPE_SENDER_PROTOCOL_SETTINGS = 0x08 |
70 FRAME_TYPE_SENDER_PROTOCOL_SETTINGS = 0x08 |
64 FRAME_TYPE_STREAM_SETTINGS = 0x09 |
71 FRAME_TYPE_STREAM_SETTINGS = 0x09 |
65 |
72 |
66 FRAME_TYPES = { |
73 FRAME_TYPES: dict[bytes, int] = { |
67 b'command-request': FRAME_TYPE_COMMAND_REQUEST, |
74 b'command-request': FRAME_TYPE_COMMAND_REQUEST, |
68 b'command-data': FRAME_TYPE_COMMAND_DATA, |
75 b'command-data': FRAME_TYPE_COMMAND_DATA, |
69 b'command-response': FRAME_TYPE_COMMAND_RESPONSE, |
76 b'command-response': FRAME_TYPE_COMMAND_RESPONSE, |
70 b'error-response': FRAME_TYPE_ERROR_RESPONSE, |
77 b'error-response': FRAME_TYPE_ERROR_RESPONSE, |
71 b'text-output': FRAME_TYPE_TEXT_OUTPUT, |
78 b'text-output': FRAME_TYPE_TEXT_OUTPUT, |
77 FLAG_COMMAND_REQUEST_NEW = 0x01 |
84 FLAG_COMMAND_REQUEST_NEW = 0x01 |
78 FLAG_COMMAND_REQUEST_CONTINUATION = 0x02 |
85 FLAG_COMMAND_REQUEST_CONTINUATION = 0x02 |
79 FLAG_COMMAND_REQUEST_MORE_FRAMES = 0x04 |
86 FLAG_COMMAND_REQUEST_MORE_FRAMES = 0x04 |
80 FLAG_COMMAND_REQUEST_EXPECT_DATA = 0x08 |
87 FLAG_COMMAND_REQUEST_EXPECT_DATA = 0x08 |
81 |
88 |
82 FLAGS_COMMAND_REQUEST = { |
89 FLAGS_COMMAND_REQUEST: dict[bytes, int] = { |
83 b'new': FLAG_COMMAND_REQUEST_NEW, |
90 b'new': FLAG_COMMAND_REQUEST_NEW, |
84 b'continuation': FLAG_COMMAND_REQUEST_CONTINUATION, |
91 b'continuation': FLAG_COMMAND_REQUEST_CONTINUATION, |
85 b'more': FLAG_COMMAND_REQUEST_MORE_FRAMES, |
92 b'more': FLAG_COMMAND_REQUEST_MORE_FRAMES, |
86 b'have-data': FLAG_COMMAND_REQUEST_EXPECT_DATA, |
93 b'have-data': FLAG_COMMAND_REQUEST_EXPECT_DATA, |
87 } |
94 } |
88 |
95 |
89 FLAG_COMMAND_DATA_CONTINUATION = 0x01 |
96 FLAG_COMMAND_DATA_CONTINUATION = 0x01 |
90 FLAG_COMMAND_DATA_EOS = 0x02 |
97 FLAG_COMMAND_DATA_EOS = 0x02 |
91 |
98 |
92 FLAGS_COMMAND_DATA = { |
99 FLAGS_COMMAND_DATA: dict[bytes, int] = { |
93 b'continuation': FLAG_COMMAND_DATA_CONTINUATION, |
100 b'continuation': FLAG_COMMAND_DATA_CONTINUATION, |
94 b'eos': FLAG_COMMAND_DATA_EOS, |
101 b'eos': FLAG_COMMAND_DATA_EOS, |
95 } |
102 } |
96 |
103 |
97 FLAG_COMMAND_RESPONSE_CONTINUATION = 0x01 |
104 FLAG_COMMAND_RESPONSE_CONTINUATION = 0x01 |
98 FLAG_COMMAND_RESPONSE_EOS = 0x02 |
105 FLAG_COMMAND_RESPONSE_EOS = 0x02 |
99 |
106 |
100 FLAGS_COMMAND_RESPONSE = { |
107 FLAGS_COMMAND_RESPONSE: dict[bytes, int] = { |
101 b'continuation': FLAG_COMMAND_RESPONSE_CONTINUATION, |
108 b'continuation': FLAG_COMMAND_RESPONSE_CONTINUATION, |
102 b'eos': FLAG_COMMAND_RESPONSE_EOS, |
109 b'eos': FLAG_COMMAND_RESPONSE_EOS, |
103 } |
110 } |
104 |
111 |
105 FLAG_SENDER_PROTOCOL_SETTINGS_CONTINUATION = 0x01 |
112 FLAG_SENDER_PROTOCOL_SETTINGS_CONTINUATION = 0x01 |
106 FLAG_SENDER_PROTOCOL_SETTINGS_EOS = 0x02 |
113 FLAG_SENDER_PROTOCOL_SETTINGS_EOS = 0x02 |
107 |
114 |
108 FLAGS_SENDER_PROTOCOL_SETTINGS = { |
115 FLAGS_SENDER_PROTOCOL_SETTINGS: dict[bytes, int] = { |
109 b'continuation': FLAG_SENDER_PROTOCOL_SETTINGS_CONTINUATION, |
116 b'continuation': FLAG_SENDER_PROTOCOL_SETTINGS_CONTINUATION, |
110 b'eos': FLAG_SENDER_PROTOCOL_SETTINGS_EOS, |
117 b'eos': FLAG_SENDER_PROTOCOL_SETTINGS_EOS, |
111 } |
118 } |
112 |
119 |
113 FLAG_STREAM_ENCODING_SETTINGS_CONTINUATION = 0x01 |
120 FLAG_STREAM_ENCODING_SETTINGS_CONTINUATION = 0x01 |
114 FLAG_STREAM_ENCODING_SETTINGS_EOS = 0x02 |
121 FLAG_STREAM_ENCODING_SETTINGS_EOS = 0x02 |
115 |
122 |
116 FLAGS_STREAM_ENCODING_SETTINGS = { |
123 FLAGS_STREAM_ENCODING_SETTINGS: dict[bytes, int] = { |
117 b'continuation': FLAG_STREAM_ENCODING_SETTINGS_CONTINUATION, |
124 b'continuation': FLAG_STREAM_ENCODING_SETTINGS_CONTINUATION, |
118 b'eos': FLAG_STREAM_ENCODING_SETTINGS_EOS, |
125 b'eos': FLAG_STREAM_ENCODING_SETTINGS_EOS, |
119 } |
126 } |
120 |
127 |
121 # Maps frame types to their available flags. |
128 # Maps frame types to their available flags. |
122 FRAME_TYPE_FLAGS = { |
129 FRAME_TYPE_FLAGS: dict[int, dict[bytes, int]] = { |
123 FRAME_TYPE_COMMAND_REQUEST: FLAGS_COMMAND_REQUEST, |
130 FRAME_TYPE_COMMAND_REQUEST: FLAGS_COMMAND_REQUEST, |
124 FRAME_TYPE_COMMAND_DATA: FLAGS_COMMAND_DATA, |
131 FRAME_TYPE_COMMAND_DATA: FLAGS_COMMAND_DATA, |
125 FRAME_TYPE_COMMAND_RESPONSE: FLAGS_COMMAND_RESPONSE, |
132 FRAME_TYPE_COMMAND_RESPONSE: FLAGS_COMMAND_RESPONSE, |
126 FRAME_TYPE_ERROR_RESPONSE: {}, |
133 FRAME_TYPE_ERROR_RESPONSE: {}, |
127 FRAME_TYPE_TEXT_OUTPUT: {}, |
134 FRAME_TYPE_TEXT_OUTPUT: {}, |
131 } |
138 } |
132 |
139 |
133 ARGUMENT_RECORD_HEADER = struct.Struct('<HH') |
140 ARGUMENT_RECORD_HEADER = struct.Struct('<HH') |
134 |
141 |
135 |
142 |
136 def humanflags(mapping, value): |
143 def humanflags(mapping: dict[bytes, int], value: int) -> bytes: |
137 """Convert a numeric flags value to a human value, using a mapping table.""" |
144 """Convert a numeric flags value to a human value, using a mapping table.""" |
138 namemap = {v: k for k, v in mapping.items()} |
145 namemap = {v: k for k, v in mapping.items()} |
139 flags = [] |
146 flags = [] |
140 val = 1 |
147 val = 1 |
141 while value >= val: |
148 while value >= val: |
148 |
155 |
149 @attr.s(slots=True) |
156 @attr.s(slots=True) |
150 class frameheader: |
157 class frameheader: |
151 """Represents the data in a frame header.""" |
158 """Represents the data in a frame header.""" |
152 |
159 |
153 length = attr.ib() |
160 length = attr.ib(type=int) |
154 requestid = attr.ib() |
161 requestid = attr.ib(type=int) |
155 streamid = attr.ib() |
162 streamid = attr.ib(type=int) |
156 streamflags = attr.ib() |
163 streamflags = attr.ib(type=int) |
157 typeid = attr.ib() |
164 typeid = attr.ib(type=int) |
158 flags = attr.ib() |
165 flags = attr.ib(type=int) |
159 |
166 |
160 |
167 |
161 @attr.s(slots=True, repr=False) |
168 @attr.s(slots=True, repr=False) |
162 class frame: |
169 class frame: |
163 """Represents a parsed frame.""" |
170 """Represents a parsed frame.""" |
164 |
171 |
165 requestid = attr.ib() |
172 requestid = attr.ib(type=int) |
166 streamid = attr.ib() |
173 streamid = attr.ib(type=int) |
167 streamflags = attr.ib() |
174 streamflags = attr.ib(type=int) |
168 typeid = attr.ib() |
175 typeid = attr.ib(type=int) |
169 flags = attr.ib() |
176 flags = attr.ib(type=int) |
170 payload = attr.ib() |
177 payload = attr.ib(type=bytes) |
171 |
178 |
172 @encoding.strmethod |
179 @encoding.strmethod |
173 def __repr__(self): |
180 def __repr__(self): |
174 typename = b'<unknown 0x%02x>' % self.typeid |
181 typename = b'<unknown 0x%02x>' % self.typeid |
175 for name, value in FRAME_TYPES.items(): |
182 for name, value in FRAME_TYPES.items(): |
189 humanflags(FRAME_TYPE_FLAGS.get(self.typeid, {}), self.flags), |
196 humanflags(FRAME_TYPE_FLAGS.get(self.typeid, {}), self.flags), |
190 ) |
197 ) |
191 ) |
198 ) |
192 |
199 |
193 |
200 |
194 def makeframe(requestid, streamid, streamflags, typeid, flags, payload): |
201 def makeframe( |
202 requestid: int, |
|
203 streamid: int, |
|
204 streamflags: int, |
|
205 typeid: int, |
|
206 flags: int, |
|
207 payload: bytes, |
|
208 ) -> bytearray: |
|
195 """Assemble a frame into a byte array.""" |
209 """Assemble a frame into a byte array.""" |
196 # TODO assert size of payload. |
210 # TODO assert size of payload. |
197 frame = bytearray(FRAME_HEADER_SIZE + len(payload)) |
211 frame = bytearray(FRAME_HEADER_SIZE + len(payload)) |
198 |
212 |
199 # 24 bits length |
213 # 24 bits length |
210 frame[8:] = payload |
224 frame[8:] = payload |
211 |
225 |
212 return frame |
226 return frame |
213 |
227 |
214 |
228 |
215 def makeframefromhumanstring(s): |
229 def makeframefromhumanstring(s: bytes) -> bytearray: |
216 """Create a frame from a human readable string |
230 """Create a frame from a human readable string |
217 |
231 |
218 Strings have the form: |
232 Strings have the form: |
219 |
233 |
220 <request-id> <stream-id> <stream-flags> <type> <flags> <payload> |
234 <request-id> <stream-id> <stream-flags> <type> <flags> <payload> |
276 flags=finalflags, |
290 flags=finalflags, |
277 payload=payload, |
291 payload=payload, |
278 ) |
292 ) |
279 |
293 |
280 |
294 |
281 def parseheader(data): |
295 def parseheader(data: bytes) -> frameheader: |
282 """Parse a unified framing protocol frame header from a buffer. |
296 """Parse a unified framing protocol frame header from a buffer. |
283 |
297 |
284 The header is expected to be in the buffer at offset 0 and the |
298 The header is expected to be in the buffer at offset 0 and the |
285 buffer is expected to be large enough to hold a full header. |
299 buffer is expected to be large enough to hold a full header. |
286 """ |
300 """ |
301 return frameheader( |
315 return frameheader( |
302 framelength, requestid, streamid, streamflags, frametype, frameflags |
316 framelength, requestid, streamid, streamflags, frametype, frameflags |
303 ) |
317 ) |
304 |
318 |
305 |
319 |
306 def readframe(fh): |
320 def readframe(fh) -> frame | None: |
307 """Read a unified framing protocol frame from a file object. |
321 """Read a unified framing protocol frame from a file object. |
308 |
322 |
309 Returns a 3-tuple of (type, flags, payload) for the decoded frame or |
323 Returns a 3-tuple of (type, flags, payload) for the decoded frame or |
310 None if no frame is available. May raise if a malformed frame is |
324 None if no frame is available. May raise if a malformed frame is |
311 seen. |
325 seen. |
336 h.requestid, h.streamid, h.streamflags, h.typeid, h.flags, payload |
350 h.requestid, h.streamid, h.streamflags, h.typeid, h.flags, payload |
337 ) |
351 ) |
338 |
352 |
339 |
353 |
340 def createcommandframes( |
354 def createcommandframes( |
341 stream, |
355 stream: stream, |
342 requestid, |
356 requestid: int, |
343 cmd, |
357 cmd, |
344 args, |
358 args, |
345 datafh=None, |
359 datafh=None, |
346 maxframesize=DEFAULT_MAX_FRAME_SIZE, |
360 maxframesize: int = DEFAULT_MAX_FRAME_SIZE, |
347 redirect=None, |
361 redirect=None, |
348 ): |
362 ) -> Iterator[bytearray]: |
349 """Create frames necessary to transmit a request to run a command. |
363 """Create frames necessary to transmit a request to run a command. |
350 |
364 |
351 This is a generator of bytearrays. Each item represents a frame |
365 This is a generator of bytearrays. Each item represents a frame |
352 ready to be sent over the wire to a peer. |
366 ready to be sent over the wire to a peer. |
353 """ |
367 """ |
412 |
426 |
413 if done: |
427 if done: |
414 break |
428 break |
415 |
429 |
416 |
430 |
417 def createcommandresponseokframe(stream, requestid): |
431 def createcommandresponseokframe( |
432 stream: outputstream, requestid: int |
|
433 ) -> bytearray | None: |
|
418 overall = b''.join(cborutil.streamencode({b'status': b'ok'})) |
434 overall = b''.join(cborutil.streamencode({b'status': b'ok'})) |
419 |
435 |
420 if stream.streamsettingssent: |
436 if stream.streamsettingssent: |
421 overall = stream.encode(overall) |
437 overall = stream.encode(overall) |
422 encoded = True |
438 encoded = True |
434 encoded=encoded, |
450 encoded=encoded, |
435 ) |
451 ) |
436 |
452 |
437 |
453 |
438 def createcommandresponseeosframes( |
454 def createcommandresponseeosframes( |
439 stream, requestid, maxframesize=DEFAULT_MAX_FRAME_SIZE |
455 stream: outputstream, |
440 ): |
456 requestid: int, |
457 maxframesize: int = DEFAULT_MAX_FRAME_SIZE, |
|
458 ) -> Iterator[bytearray]: |
|
441 """Create an empty payload frame representing command end-of-stream.""" |
459 """Create an empty payload frame representing command end-of-stream.""" |
442 payload = stream.flush() |
460 payload = stream.flush() |
443 |
461 |
444 offset = 0 |
462 offset = 0 |
445 while True: |
463 while True: |
463 |
481 |
464 if done: |
482 if done: |
465 break |
483 break |
466 |
484 |
467 |
485 |
468 def createalternatelocationresponseframe(stream, requestid, location): |
486 def createalternatelocationresponseframe( |
487 stream: outputstream, requestid: int, location |
|
488 ) -> bytearray: |
|
469 data = { |
489 data = { |
470 b'status': b'redirect', |
490 b'status': b'redirect', |
471 b'location': { |
491 b'location': { |
472 b'url': location.url, |
492 b'url': location.url, |
473 b'mediatype': location.mediatype, |
493 b'mediatype': location.mediatype, |
502 payload=payload, |
522 payload=payload, |
503 encoded=encoded, |
523 encoded=encoded, |
504 ) |
524 ) |
505 |
525 |
506 |
526 |
507 def createcommanderrorresponse(stream, requestid, message, args=None): |
527 def createcommanderrorresponse( |
528 stream: stream, requestid: int, message: bytes, args=None |
|
529 ) -> Iterator[bytearray]: |
|
508 # TODO should this be using a list of {'msg': ..., 'args': {}} so atom |
530 # TODO should this be using a list of {'msg': ..., 'args': {}} so atom |
509 # formatting works consistently? |
531 # formatting works consistently? |
510 m = { |
532 m = { |
511 b'status': b'error', |
533 b'status': b'error', |
512 b'error': { |
534 b'error': { |
525 flags=FLAG_COMMAND_RESPONSE_EOS, |
547 flags=FLAG_COMMAND_RESPONSE_EOS, |
526 payload=overall, |
548 payload=overall, |
527 ) |
549 ) |
528 |
550 |
529 |
551 |
530 def createerrorframe(stream, requestid, msg, errtype): |
552 def createerrorframe( |
553 stream: stream, requestid: int, msg: bytes, errtype: bytes |
|
554 ) -> Iterator[bytearray]: |
|
531 # TODO properly handle frame size limits. |
555 # TODO properly handle frame size limits. |
532 assert len(msg) <= DEFAULT_MAX_FRAME_SIZE |
556 assert len(msg) <= DEFAULT_MAX_FRAME_SIZE |
533 |
557 |
534 payload = b''.join( |
558 payload = b''.join( |
535 cborutil.streamencode( |
559 cborutil.streamencode( |
547 payload=payload, |
571 payload=payload, |
548 ) |
572 ) |
549 |
573 |
550 |
574 |
551 def createtextoutputframe( |
575 def createtextoutputframe( |
552 stream, requestid, atoms, maxframesize=DEFAULT_MAX_FRAME_SIZE |
576 stream: stream, |
553 ): |
577 requestid: int, |
578 atoms, |
|
579 maxframesize: int = DEFAULT_MAX_FRAME_SIZE, |
|
580 ) -> Iterator[bytearray]: |
|
554 """Create a text output frame to render text to people. |
581 """Create a text output frame to render text to people. |
555 |
582 |
556 ``atoms`` is a 3-tuple of (formatting string, args, labels). |
583 ``atoms`` is a 3-tuple of (formatting string, args, labels). |
557 |
584 |
558 The formatting string contains ``%s`` tokens to be replaced by the |
585 The formatting string contains ``%s`` tokens to be replaced by the |
614 TODO we'll need something like this when compression is supported. |
641 TODO we'll need something like this when compression is supported. |
615 So it might make sense to implement this functionality at the stream |
642 So it might make sense to implement this functionality at the stream |
616 level. |
643 level. |
617 """ |
644 """ |
618 |
645 |
619 def __init__(self, stream, requestid, maxframesize=DEFAULT_MAX_FRAME_SIZE): |
646 def __init__( |
647 self, stream, requestid: int, maxframesize: int = DEFAULT_MAX_FRAME_SIZE |
|
648 ) -> None: |
|
620 self._stream = stream |
649 self._stream = stream |
621 self._requestid = requestid |
650 self._requestid = requestid |
622 self._maxsize = maxframesize |
651 self._maxsize = maxframesize |
623 self._chunks = [] |
652 self._chunks = [] |
624 self._chunkssize = 0 |
653 self._chunkssize = 0 |
859 # this module. |
888 # this module. |
860 STREAM_ENCODERS: dict[bytes, tuple[EncoderT, DecoderT]] = {} |
889 STREAM_ENCODERS: dict[bytes, tuple[EncoderT, DecoderT]] = {} |
861 STREAM_ENCODERS_ORDER: list[bytes] = [] |
890 STREAM_ENCODERS_ORDER: list[bytes] = [] |
862 |
891 |
863 |
892 |
864 def populatestreamencoders(): |
893 def populatestreamencoders() -> None: |
865 if STREAM_ENCODERS: |
894 if STREAM_ENCODERS: |
866 return |
895 return |
867 |
896 |
868 try: |
897 try: |
869 from . import zstd # pytype: disable=import-error |
898 from . import zstd # pytype: disable=import-error |
885 |
914 |
886 |
915 |
887 class stream: |
916 class stream: |
888 """Represents a logical unidirectional series of frames.""" |
917 """Represents a logical unidirectional series of frames.""" |
889 |
918 |
890 def __init__(self, streamid, active=False): |
919 streamid: int |
920 _active: bool |
|
921 |
|
922 def __init__(self, streamid: int, active: bool = False) -> None: |
|
891 self.streamid = streamid |
923 self.streamid = streamid |
892 self._active = active |
924 self._active = active |
893 |
925 |
894 def makeframe(self, requestid, typeid, flags, payload): |
926 def makeframe( |
927 self, requestid: int, typeid: int, flags: int, payload: bytes |
|
928 ) -> bytearray: |
|
895 """Create a frame to be sent out over this stream. |
929 """Create a frame to be sent out over this stream. |
896 |
930 |
897 Only returns the frame instance. Does not actually send it. |
931 Only returns the frame instance. Does not actually send it. |
898 """ |
932 """ |
899 streamflags = 0 |
933 streamflags = 0 |
907 |
941 |
908 |
942 |
909 class inputstream(stream): |
943 class inputstream(stream): |
910 """Represents a stream used for receiving data.""" |
944 """Represents a stream used for receiving data.""" |
911 |
945 |
912 def __init__(self, streamid, active=False): |
946 _decoder: Decoder | None |
947 |
|
948 def __init__(self, streamid: int, active: bool = False) -> None: |
|
913 super().__init__(streamid, active=active) |
949 super().__init__(streamid, active=active) |
914 self._decoder = None |
950 self._decoder = None |
915 |
951 |
916 def setdecoder(self, ui, name, extraobjs): |
952 def setdecoder(self, ui, name: bytes, extraobjs) -> None: |
917 """Set the decoder for this stream. |
953 """Set the decoder for this stream. |
918 |
954 |
919 Receives the stream profile name and any additional CBOR objects |
955 Receives the stream profile name and any additional CBOR objects |
920 decoded from the stream encoding settings frame payloads. |
956 decoded from the stream encoding settings frame payloads. |
921 """ |
957 """ |
922 if name not in STREAM_ENCODERS: |
958 if name not in STREAM_ENCODERS: |
923 raise error.Abort(_(b'unknown stream decoder: %s') % name) |
959 raise error.Abort(_(b'unknown stream decoder: %s') % name) |
924 |
960 |
925 self._decoder = STREAM_ENCODERS[name][1](ui, extraobjs) |
961 self._decoder = STREAM_ENCODERS[name][1](ui, extraobjs) |
926 |
962 |
927 def decode(self, data): |
963 def decode(self, data) -> bytes: |
928 # Default is identity decoder. We don't bother instantiating one |
964 # Default is identity decoder. We don't bother instantiating one |
929 # because it is trivial. |
965 # because it is trivial. |
930 if not self._decoder: |
966 if not self._decoder: |
931 return data |
967 return data |
932 |
968 |
933 return self._decoder.decode(data) |
969 return self._decoder.decode(data) |
934 |
970 |
935 def flush(self): |
971 def flush(self) -> bytes: |
936 if not self._decoder: |
972 if not self._decoder: |
937 return b'' |
973 return b'' |
938 |
974 |
975 # TODO: this looks like a bug- no decoder class defines flush(), so |
|
976 # either no decoders are used, or no inputstream is flushed. |
|
939 return self._decoder.flush() |
977 return self._decoder.flush() |
940 |
978 |
941 |
979 |
942 class outputstream(stream): |
980 class outputstream(stream): |
943 """Represents a stream used for sending data.""" |
981 """Represents a stream used for sending data.""" |
944 |
982 |
945 def __init__(self, streamid, active=False): |
983 streamsettingssent: bool |
984 _encoder: Encoder | None |
|
985 _encodername: bytes | None |
|
986 |
|
987 def __init__(self, streamid: int, active: bool = False) -> None: |
|
946 super().__init__(streamid, active=active) |
988 super().__init__(streamid, active=active) |
947 self.streamsettingssent = False |
989 self.streamsettingssent = False |
948 self._encoder = None |
990 self._encoder = None |
949 self._encodername = None |
991 self._encodername = None |
950 |
992 |
951 def setencoder(self, ui, name): |
993 def setencoder(self, ui, name: bytes) -> None: |
952 """Set the encoder for this stream. |
994 """Set the encoder for this stream. |
953 |
995 |
954 Receives the stream profile name. |
996 Receives the stream profile name. |
955 """ |
997 """ |
956 if name not in STREAM_ENCODERS: |
998 if name not in STREAM_ENCODERS: |
957 raise error.Abort(_(b'unknown stream encoder: %s') % name) |
999 raise error.Abort(_(b'unknown stream encoder: %s') % name) |
958 |
1000 |
959 self._encoder = STREAM_ENCODERS[name][0](ui) |
1001 self._encoder = STREAM_ENCODERS[name][0](ui) |
960 self._encodername = name |
1002 self._encodername = name |
961 |
1003 |
962 def encode(self, data): |
1004 def encode(self, data) -> bytes: |
963 if not self._encoder: |
1005 if not self._encoder: |
964 return data |
1006 return data |
965 |
1007 |
966 return self._encoder.encode(data) |
1008 return self._encoder.encode(data) |
967 |
1009 |
968 def flush(self): |
1010 def flush(self) -> bytes: |
969 if not self._encoder: |
1011 if not self._encoder: |
970 return b'' |
1012 return b'' |
971 |
1013 |
972 return self._encoder.flush() |
1014 return self._encoder.flush() |
973 |
1015 |
974 def finish(self): |
1016 # TODO: was this supposed to return the result of finish()? |
1017 def finish(self): # -> bytes: |
|
975 if not self._encoder: |
1018 if not self._encoder: |
976 return b'' |
1019 return b'' |
977 |
1020 |
978 self._encoder.finish() |
1021 self._encoder.finish() |
979 |
1022 |
980 def makeframe(self, requestid, typeid, flags, payload, encoded=False): |
1023 def makeframe( |
1024 self, |
|
1025 requestid: int, |
|
1026 typeid: int, |
|
1027 flags: int, |
|
1028 payload: bytes, |
|
1029 encoded: bool = False, |
|
1030 ) -> bytearray: |
|
981 """Create a frame to be sent out over this stream. |
1031 """Create a frame to be sent out over this stream. |
982 |
1032 |
983 Only returns the frame instance. Does not actually send it. |
1033 Only returns the frame instance. Does not actually send it. |
984 """ |
1034 """ |
985 streamflags = 0 |
1035 streamflags = 0 |
1004 |
1054 |
1005 return makeframe( |
1055 return makeframe( |
1006 requestid, self.streamid, streamflags, typeid, flags, payload |
1056 requestid, self.streamid, streamflags, typeid, flags, payload |
1007 ) |
1057 ) |
1008 |
1058 |
1009 def makestreamsettingsframe(self, requestid): |
1059 def makestreamsettingsframe(self, requestid: int) -> bytearray | None: |
1010 """Create a stream settings frame for this stream. |
1060 """Create a stream settings frame for this stream. |
1011 |
1061 |
1012 Returns frame data or None if no stream settings frame is needed or has |
1062 Returns frame data or None if no stream settings frame is needed or has |
1013 already been sent. |
1063 already been sent. |
1014 """ |
1064 """ |
1022 FLAG_STREAM_ENCODING_SETTINGS_EOS, |
1072 FLAG_STREAM_ENCODING_SETTINGS_EOS, |
1023 payload, |
1073 payload, |
1024 ) |
1074 ) |
1025 |
1075 |
1026 |
1076 |
1027 def ensureserverstream(stream): |
1077 def ensureserverstream(stream: stream) -> None: |
1028 if stream.streamid % 2: |
1078 if stream.streamid % 2: |
1029 raise error.ProgrammingError( |
1079 raise error.ProgrammingError( |
1030 b'server should only write to even ' |
1080 b'server should only write to even ' |
1031 b'numbered streams; %d is not even' % stream.streamid |
1081 b'numbered streams; %d is not even' % stream.streamid |
1032 ) |
1082 ) |
1033 |
1083 |
1034 |
1084 |
1035 DEFAULT_PROTOCOL_SETTINGS = { |
1085 DEFAULT_PROTOCOL_SETTINGS: dict[bytes, list[bytes]] = { |
1036 b'contentencodings': [b'identity'], |
1086 b'contentencodings': [b'identity'], |
1037 } |
1087 } |
1038 |
1088 |
1039 |
1089 |
1040 class serverreactor: |
1090 class serverreactor: |
1100 that if we receive a command and instruct its dispatch, another command |
1150 that if we receive a command and instruct its dispatch, another command |
1101 with its request ID can come in over the wire and there will be a race |
1151 with its request ID can come in over the wire and there will be a race |
1102 between who responds to what. |
1152 between who responds to what. |
1103 """ |
1153 """ |
1104 |
1154 |
1105 def __init__(self, ui, deferoutput=False): |
1155 _bufferedframegens: list[Iterator[bytearray]] |
1156 |
|
1157 def __init__(self, ui, deferoutput: bool = False) -> None: |
|
1106 """Construct a new server reactor. |
1158 """Construct a new server reactor. |
1107 |
1159 |
1108 ``deferoutput`` can be used to indicate that no output frames should be |
1160 ``deferoutput`` can be used to indicate that no output frames should be |
1109 instructed to be sent until input has been exhausted. In this mode, |
1161 instructed to be sent until input has been exhausted. In this mode, |
1110 events that would normally generate output frames (such as a command |
1162 events that would normally generate output frames (such as a command |
1132 # Sender protocol settings are optional. Set implied default values. |
1184 # Sender protocol settings are optional. Set implied default values. |
1133 self._sendersettings = dict(DEFAULT_PROTOCOL_SETTINGS) |
1185 self._sendersettings = dict(DEFAULT_PROTOCOL_SETTINGS) |
1134 |
1186 |
1135 populatestreamencoders() |
1187 populatestreamencoders() |
1136 |
1188 |
1137 def onframerecv(self, frame): |
1189 def onframerecv(self, frame: frame): |
1138 """Process a frame that has been received off the wire. |
1190 """Process a frame that has been received off the wire. |
1139 |
1191 |
1140 Returns a dict with an ``action`` key that details what action, |
1192 Returns a dict with an ``action`` key that details what action, |
1141 if any, the consumer should take next. |
1193 if any, the consumer should take next. |
1142 """ |
1194 """ |
1181 if not meth: |
1233 if not meth: |
1182 raise error.ProgrammingError(b'unhandled state: %s' % self._state) |
1234 raise error.ProgrammingError(b'unhandled state: %s' % self._state) |
1183 |
1235 |
1184 return meth(frame) |
1236 return meth(frame) |
1185 |
1237 |
1186 def oncommandresponsereadyobjects(self, stream, requestid, objs): |
1238 def oncommandresponsereadyobjects( |
1239 self, stream, requestid: int, objs |
|
1240 ) -> HandleSendFramesReturnT: |
|
1187 """Signal that objects are ready to be sent to the client. |
1241 """Signal that objects are ready to be sent to the client. |
1188 |
1242 |
1189 ``objs`` is an iterable of objects (typically a generator) that will |
1243 ``objs`` is an iterable of objects (typically a generator) that will |
1190 be encoded via CBOR and added to frames, which will be sent to the |
1244 be encoded via CBOR and added to frames, which will be sent to the |
1191 client. |
1245 client. |
1320 |
1374 |
1321 self._activecommands.remove(requestid) |
1375 self._activecommands.remove(requestid) |
1322 |
1376 |
1323 return self._handlesendframes(sendframes()) |
1377 return self._handlesendframes(sendframes()) |
1324 |
1378 |
1325 def oninputeof(self): |
1379 def oninputeof(self) -> tuple[bytes, dict[bytes, Iterator[bytearray]]]: |
1326 """Signals that end of input has been received. |
1380 """Signals that end of input has been received. |
1327 |
1381 |
1328 No more frames will be received. All pending activity should be |
1382 No more frames will be received. All pending activity should be |
1329 completed. |
1383 completed. |
1330 """ |
1384 """ |
1340 |
1394 |
1341 return b'sendframes', { |
1395 return b'sendframes', { |
1342 b'framegen': makegen(), |
1396 b'framegen': makegen(), |
1343 } |
1397 } |
1344 |
1398 |
1345 def _handlesendframes(self, framegen): |
1399 def _handlesendframes( |
1400 self, framegen: Iterator[bytearray] |
|
1401 ) -> HandleSendFramesReturnT: |
|
1346 if self._deferoutput: |
1402 if self._deferoutput: |
1347 self._bufferedframegens.append(framegen) |
1403 self._bufferedframegens.append(framegen) |
1348 return b'noop', {} |
1404 return b'noop', {} |
1349 else: |
1405 else: |
1350 return b'sendframes', { |
1406 return b'sendframes', { |
1351 b'framegen': framegen, |
1407 b'framegen': framegen, |
1352 } |
1408 } |
1353 |
1409 |
1354 def onservererror(self, stream, requestid, msg): |
1410 def onservererror( |
1411 self, stream: stream, requestid: int, msg: bytes |
|
1412 ) -> HandleSendFramesReturnT: |
|
1355 ensureserverstream(stream) |
1413 ensureserverstream(stream) |
1356 |
1414 |
1357 def sendframes(): |
1415 def sendframes(): |
1358 yield from createerrorframe( |
1416 yield from createerrorframe( |
1359 stream, requestid, msg, errtype=b'server' |
1417 stream, requestid, msg, errtype=b'server' |
1361 |
1419 |
1362 self._activecommands.remove(requestid) |
1420 self._activecommands.remove(requestid) |
1363 |
1421 |
1364 return self._handlesendframes(sendframes()) |
1422 return self._handlesendframes(sendframes()) |
1365 |
1423 |
1366 def oncommanderror(self, stream, requestid, message, args=None): |
1424 def oncommanderror( |
1425 self, stream: stream, requestid: int, message: bytes, args=None |
|
1426 ) -> HandleSendFramesReturnT: |
|
1367 """Called when a command encountered an error before sending output.""" |
1427 """Called when a command encountered an error before sending output.""" |
1368 ensureserverstream(stream) |
1428 ensureserverstream(stream) |
1369 |
1429 |
1370 def sendframes(): |
1430 def sendframes(): |
1371 yield from createcommanderrorresponse( |
1431 yield from createcommanderrorresponse( |
1374 |
1434 |
1375 self._activecommands.remove(requestid) |
1435 self._activecommands.remove(requestid) |
1376 |
1436 |
1377 return self._handlesendframes(sendframes()) |
1437 return self._handlesendframes(sendframes()) |
1378 |
1438 |
1379 def makeoutputstream(self): |
1439 def makeoutputstream(self) -> outputstream: |
1380 """Create a stream to be used for sending data to the client. |
1440 """Create a stream to be used for sending data to the client. |
1381 |
1441 |
1382 If this is called before protocol settings frames are received, we |
1442 If this is called before protocol settings frames are received, we |
1383 don't know what stream encodings are supported by the client and |
1443 don't know what stream encodings are supported by the client and |
1384 we will default to identity. |
1444 we will default to identity. |
1396 s.setencoder(self._ui, name) |
1456 s.setencoder(self._ui, name) |
1397 break |
1457 break |
1398 |
1458 |
1399 return s |
1459 return s |
1400 |
1460 |
1401 def _makeerrorresult(self, msg): |
1461 def _makeerrorresult(self, msg: bytes) -> tuple[bytes, dict[bytes, bytes]]: |
1402 return b'error', { |
1462 return b'error', { |
1403 b'message': msg, |
1463 b'message': msg, |
1404 } |
1464 } |
1405 |
1465 |
1406 def _makeruncommandresult(self, requestid): |
1466 def _makeruncommandresult(self, requestid: int): |
1407 entry = self._receivingcommands[requestid] |
1467 entry = self._receivingcommands[requestid] |
1408 |
1468 |
1409 if not entry[b'requestdone']: |
1469 if not entry[b'requestdone']: |
1410 self._state = b'errored' |
1470 self._state = b'errored' |
1411 raise error.ProgrammingError( |
1471 raise error.ProgrammingError( |
1444 b'redirect': request.get(b'redirect'), |
1504 b'redirect': request.get(b'redirect'), |
1445 b'data': entry[b'data'].getvalue() if entry[b'data'] else None, |
1505 b'data': entry[b'data'].getvalue() if entry[b'data'] else None, |
1446 }, |
1506 }, |
1447 ) |
1507 ) |
1448 |
1508 |
1449 def _makewantframeresult(self): |
1509 def _makewantframeresult(self) -> tuple[bytes, dict[bytes, bytes]]: |
1450 return b'wantframe', { |
1510 return b'wantframe', { |
1451 b'state': self._state, |
1511 b'state': self._state, |
1452 } |
1512 } |
1453 |
1513 |
1454 def _validatecommandrequestframe(self, frame): |
1514 def _validatecommandrequestframe(self, frame: frame): |
1455 new = frame.flags & FLAG_COMMAND_REQUEST_NEW |
1515 new = frame.flags & FLAG_COMMAND_REQUEST_NEW |
1456 continuation = frame.flags & FLAG_COMMAND_REQUEST_CONTINUATION |
1516 continuation = frame.flags & FLAG_COMMAND_REQUEST_CONTINUATION |
1457 |
1517 |
1458 if new and continuation: |
1518 if new and continuation: |
1459 self._state = b'errored' |
1519 self._state = b'errored' |
1471 b'received command request frame with neither new nor ' |
1531 b'received command request frame with neither new nor ' |
1472 b'continuation flags set' |
1532 b'continuation flags set' |
1473 ) |
1533 ) |
1474 ) |
1534 ) |
1475 |
1535 |
1476 def _onframeinitial(self, frame): |
1536 def _onframeinitial(self, frame: frame): |
1477 # Called when we receive a frame when in the "initial" state. |
1537 # Called when we receive a frame when in the "initial" state. |
1478 if frame.typeid == FRAME_TYPE_SENDER_PROTOCOL_SETTINGS: |
1538 if frame.typeid == FRAME_TYPE_SENDER_PROTOCOL_SETTINGS: |
1479 self._state = b'protocol-settings-receiving' |
1539 self._state = b'protocol-settings-receiving' |
1480 self._protocolsettingsdecoder = cborutil.bufferingdecoder() |
1540 self._protocolsettingsdecoder = cborutil.bufferingdecoder() |
1481 return self._onframeprotocolsettings(frame) |
1541 return self._onframeprotocolsettings(frame) |
1492 b'frame; got %d' |
1552 b'frame; got %d' |
1493 ) |
1553 ) |
1494 % frame.typeid |
1554 % frame.typeid |
1495 ) |
1555 ) |
1496 |
1556 |
1497 def _onframeprotocolsettings(self, frame): |
1557 def _onframeprotocolsettings(self, frame: frame): |
1498 assert self._state == b'protocol-settings-receiving' |
1558 assert self._state == b'protocol-settings-receiving' |
1499 assert self._protocolsettingsdecoder is not None |
1559 assert self._protocolsettingsdecoder is not None |
1500 |
1560 |
1501 if frame.typeid != FRAME_TYPE_SENDER_PROTOCOL_SETTINGS: |
1561 if frame.typeid != FRAME_TYPE_SENDER_PROTOCOL_SETTINGS: |
1502 self._state = b'errored' |
1562 self._state = b'errored' |
1568 |
1628 |
1569 self._state = b'idle' |
1629 self._state = b'idle' |
1570 |
1630 |
1571 return self._makewantframeresult() |
1631 return self._makewantframeresult() |
1572 |
1632 |
1573 def _onframeidle(self, frame): |
1633 def _onframeidle(self, frame: frame): |
1574 # The only frame type that should be received in this state is a |
1634 # The only frame type that should be received in this state is a |
1575 # command request. |
1635 # command request. |
1576 if frame.typeid != FRAME_TYPE_COMMAND_REQUEST: |
1636 if frame.typeid != FRAME_TYPE_COMMAND_REQUEST: |
1577 self._state = b'errored' |
1637 self._state = b'errored' |
1578 return self._makeerrorresult( |
1638 return self._makeerrorresult( |
1621 |
1681 |
1622 assert moreframes or expectingdata |
1682 assert moreframes or expectingdata |
1623 self._state = b'command-receiving' |
1683 self._state = b'command-receiving' |
1624 return self._makewantframeresult() |
1684 return self._makewantframeresult() |
1625 |
1685 |
1626 def _onframecommandreceiving(self, frame): |
1686 def _onframecommandreceiving(self, frame: frame): |
1627 if frame.typeid == FRAME_TYPE_COMMAND_REQUEST: |
1687 if frame.typeid == FRAME_TYPE_COMMAND_REQUEST: |
1628 # Process new command requests as such. |
1688 # Process new command requests as such. |
1629 if frame.flags & FLAG_COMMAND_REQUEST_NEW: |
1689 if frame.flags & FLAG_COMMAND_REQUEST_NEW: |
1630 return self._onframeidle(frame) |
1690 return self._onframeidle(frame) |
1631 |
1691 |
1699 self._state = b'errored' |
1759 self._state = b'errored' |
1700 return self._makeerrorresult( |
1760 return self._makeerrorresult( |
1701 _(b'received unexpected frame type: %d') % frame.typeid |
1761 _(b'received unexpected frame type: %d') % frame.typeid |
1702 ) |
1762 ) |
1703 |
1763 |
1704 def _handlecommanddataframe(self, frame, entry): |
1764 def _handlecommanddataframe(self, frame: frame, entry): |
1705 assert frame.typeid == FRAME_TYPE_COMMAND_DATA |
1765 assert frame.typeid == FRAME_TYPE_COMMAND_DATA |
1706 |
1766 |
1707 # TODO support streaming data instead of buffering it. |
1767 # TODO support streaming data instead of buffering it. |
1708 entry[b'data'].write(frame.payload) |
1768 entry[b'data'].write(frame.payload) |
1709 |
1769 |
1714 return self._makeruncommandresult(frame.requestid) |
1774 return self._makeruncommandresult(frame.requestid) |
1715 else: |
1775 else: |
1716 self._state = b'errored' |
1776 self._state = b'errored' |
1717 return self._makeerrorresult(_(b'command data frame without flags')) |
1777 return self._makeerrorresult(_(b'command data frame without flags')) |
1718 |
1778 |
1719 def _onframeerrored(self, frame): |
1779 def _onframeerrored(self, frame: frame): |
1720 return self._makeerrorresult(_(b'server already errored')) |
1780 return self._makeerrorresult(_(b'server already errored')) |
1721 |
1781 |
1722 |
1782 |
1723 class commandrequest: |
1783 class commandrequest: |
1724 """Represents a request to run a command.""" |
1784 """Represents a request to run a command.""" |
1725 |
1785 |
1726 def __init__(self, requestid, name, args, datafh=None, redirect=None): |
1786 state: bytes |
1787 |
|
1788 def __init__( |
|
1789 self, requestid: int, name, args, datafh=None, redirect=None |
|
1790 ) -> None: |
|
1727 self.requestid = requestid |
1791 self.requestid = requestid |
1728 self.name = name |
1792 self.name = name |
1729 self.args = args |
1793 self.args = args |
1730 self.datafh = datafh |
1794 self.datafh = datafh |
1731 self.redirect = redirect |
1795 self.redirect = redirect |
1777 ``expectmore`` and ``eos`` evaluate to True when more response data |
1841 ``expectmore`` and ``eos`` evaluate to True when more response data |
1778 is expected to follow or we're at the end of the response stream, |
1842 is expected to follow or we're at the end of the response stream, |
1779 respectively. |
1843 respectively. |
1780 """ |
1844 """ |
1781 |
1845 |
1846 _hasmultiplesend: bool |
|
1847 _buffersends: bool |
|
1848 |
|
1782 def __init__( |
1849 def __init__( |
1783 self, |
1850 self, |
1784 ui, |
1851 ui, |
1785 hasmultiplesend=False, |
1852 hasmultiplesend: bool = False, |
1786 buffersends=True, |
1853 buffersends: bool = True, |
1787 clientcontentencoders=None, |
1854 clientcontentencoders=None, |
1788 ): |
1855 ) -> None: |
1789 """Create a new instance. |
1856 """Create a new instance. |
1790 |
1857 |
1791 ``hasmultiplesend`` indicates whether multiple sends are supported |
1858 ``hasmultiplesend`` indicates whether multiple sends are supported |
1792 by the transport. When True, it is possible to send commands immediately |
1859 by the transport. When True, it is possible to send commands immediately |
1793 instead of buffering until the caller signals an intent to finish a |
1860 instead of buffering until the caller signals an intent to finish a |
1857 { |
1924 { |
1858 b'framegen': self._makecommandframes(request), |
1925 b'framegen': self._makecommandframes(request), |
1859 }, |
1926 }, |
1860 ) |
1927 ) |
1861 |
1928 |
1862 def flushcommands(self): |
1929 def flushcommands(self) -> tuple[bytes, dict[bytes, Iterator[bytearray]]]: |
1863 """Request that all queued commands be sent. |
1930 """Request that all queued commands be sent. |
1864 |
1931 |
1865 If any commands are buffered, this will instruct the caller to send |
1932 If any commands are buffered, this will instruct the caller to send |
1866 them over the wire. If no commands are buffered it instructs the client |
1933 them over the wire. If no commands are buffered it instructs the client |
1867 to no-op. |
1934 to no-op. |
1890 |
1957 |
1891 return b'sendframes', { |
1958 return b'sendframes', { |
1892 b'framegen': makeframes(), |
1959 b'framegen': makeframes(), |
1893 } |
1960 } |
1894 |
1961 |
1895 def _makecommandframes(self, request): |
1962 def _makecommandframes( |
1963 self, request: commandrequest |
|
1964 ) -> Iterator[bytearray]: |
|
1896 """Emit frames to issue a command request. |
1965 """Emit frames to issue a command request. |
1897 |
1966 |
1898 As a side-effect, update request accounting to reflect its changed |
1967 As a side-effect, update request accounting to reflect its changed |
1899 state. |
1968 state. |
1900 """ |
1969 """ |
1930 |
1999 |
1931 yield from res |
2000 yield from res |
1932 |
2001 |
1933 request.state = b'sent' |
2002 request.state = b'sent' |
1934 |
2003 |
1935 def onframerecv(self, frame): |
2004 def onframerecv(self, frame: frame): |
1936 """Process a frame that has been received off the wire. |
2005 """Process a frame that has been received off the wire. |
1937 |
2006 |
1938 Returns a 2-tuple of (action, meta) describing further action the |
2007 Returns a 2-tuple of (action, meta) describing further action the |
1939 caller needs to take as a result of receiving this frame. |
2008 caller needs to take as a result of receiving this frame. |
1940 """ |
2009 """ |
2002 b'unhandled frame type: %d' % frame.typeid |
2071 b'unhandled frame type: %d' % frame.typeid |
2003 ) |
2072 ) |
2004 |
2073 |
2005 return meth(request, frame) |
2074 return meth(request, frame) |
2006 |
2075 |
2007 def _onstreamsettingsframe(self, frame): |
2076 def _onstreamsettingsframe(self, frame: frame): |
2008 assert frame.typeid == FRAME_TYPE_STREAM_SETTINGS |
2077 assert frame.typeid == FRAME_TYPE_STREAM_SETTINGS |
2009 |
2078 |
2010 more = frame.flags & FLAG_STREAM_ENCODING_SETTINGS_CONTINUATION |
2079 more = frame.flags & FLAG_STREAM_ENCODING_SETTINGS_CONTINUATION |
2011 eos = frame.flags & FLAG_STREAM_ENCODING_SETTINGS_EOS |
2080 eos = frame.flags & FLAG_STREAM_ENCODING_SETTINGS_EOS |
2012 |
2081 |
2090 }, |
2159 }, |
2091 ) |
2160 ) |
2092 |
2161 |
2093 return b'noop', {} |
2162 return b'noop', {} |
2094 |
2163 |
2095 def _oncommandresponseframe(self, request, frame): |
2164 def _oncommandresponseframe(self, request: commandrequest, frame: frame): |
2096 if frame.flags & FLAG_COMMAND_RESPONSE_EOS: |
2165 if frame.flags & FLAG_COMMAND_RESPONSE_EOS: |
2097 request.state = b'received' |
2166 request.state = b'received' |
2098 del self._activerequests[request.requestid] |
2167 del self._activerequests[request.requestid] |
2099 |
2168 |
2100 return ( |
2169 return ( |
2105 b'eos': frame.flags & FLAG_COMMAND_RESPONSE_EOS, |
2174 b'eos': frame.flags & FLAG_COMMAND_RESPONSE_EOS, |
2106 b'data': frame.payload, |
2175 b'data': frame.payload, |
2107 }, |
2176 }, |
2108 ) |
2177 ) |
2109 |
2178 |
2110 def _onerrorresponseframe(self, request, frame): |
2179 def _onerrorresponseframe(self, request: commandrequest, frame: frame): |
2111 request.state = b'errored' |
2180 request.state = b'errored' |
2112 del self._activerequests[request.requestid] |
2181 del self._activerequests[request.requestid] |
2113 |
2182 |
2114 # The payload should be a CBOR map. |
2183 # The payload should be a CBOR map. |
2115 m = cborutil.decodeall(frame.payload)[0] |
2184 m = cborutil.decodeall(frame.payload)[0] |