mercurial/wireprotoframing.py
changeset 52699 068398a8c9cb
parent 52698 1a612f9ec2c4
equal deleted inserted replaced
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]