mercurial/wireprotoframing.py
author Yuya Nishihara <yuya@tcha.org>
Thu, 22 Mar 2018 21:56:20 +0900
changeset 37087 f0b6fbea00cf
parent 37066 39304dd63589
child 37287 3ed344546d9e
permissions -rw-r--r--
stringutil: bulk-replace call sites to point to new module This might conflict with other patches floating around, sorry.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     1
# wireprotoframing.py - unified framing protocol for wire protocol
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     2
#
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     3
# Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     4
#
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms of the
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     6
# GNU General Public License version 2 or any later version.
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     7
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     8
# This file contains functionality to support the unified frame-based wire
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     9
# protocol. For details about the protocol, see
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    10
# `hg help internals.wireprotocol`.
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    11
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    12
from __future__ import absolute_import
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    13
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    14
import struct
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    15
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
    16
from .i18n import _
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
    17
from .thirdparty import (
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
    18
    attr,
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
    19
)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    20
from . import (
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
    21
    error,
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    22
    util,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    23
)
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37066
diff changeset
    24
from .utils import (
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37066
diff changeset
    25
    stringutil,
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37066
diff changeset
    26
)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    27
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
    28
FRAME_HEADER_SIZE = 6
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    29
DEFAULT_MAX_FRAME_SIZE = 32768
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    30
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    31
FRAME_TYPE_COMMAND_NAME = 0x01
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    32
FRAME_TYPE_COMMAND_ARGUMENT = 0x02
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    33
FRAME_TYPE_COMMAND_DATA = 0x03
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    34
FRAME_TYPE_BYTES_RESPONSE = 0x04
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    35
FRAME_TYPE_ERROR_RESPONSE = 0x05
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
    36
FRAME_TYPE_TEXT_OUTPUT = 0x06
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    37
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    38
FRAME_TYPES = {
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    39
    b'command-name': FRAME_TYPE_COMMAND_NAME,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    40
    b'command-argument': FRAME_TYPE_COMMAND_ARGUMENT,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    41
    b'command-data': FRAME_TYPE_COMMAND_DATA,
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    42
    b'bytes-response': FRAME_TYPE_BYTES_RESPONSE,
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    43
    b'error-response': FRAME_TYPE_ERROR_RESPONSE,
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
    44
    b'text-output': FRAME_TYPE_TEXT_OUTPUT,
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    45
}
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    46
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    47
FLAG_COMMAND_NAME_EOS = 0x01
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    48
FLAG_COMMAND_NAME_HAVE_ARGS = 0x02
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    49
FLAG_COMMAND_NAME_HAVE_DATA = 0x04
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    50
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    51
FLAGS_COMMAND = {
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    52
    b'eos': FLAG_COMMAND_NAME_EOS,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    53
    b'have-args': FLAG_COMMAND_NAME_HAVE_ARGS,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    54
    b'have-data': FLAG_COMMAND_NAME_HAVE_DATA,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    55
}
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    56
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    57
FLAG_COMMAND_ARGUMENT_CONTINUATION = 0x01
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    58
FLAG_COMMAND_ARGUMENT_EOA = 0x02
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    59
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    60
FLAGS_COMMAND_ARGUMENT = {
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    61
    b'continuation': FLAG_COMMAND_ARGUMENT_CONTINUATION,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    62
    b'eoa': FLAG_COMMAND_ARGUMENT_EOA,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    63
}
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    64
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    65
FLAG_COMMAND_DATA_CONTINUATION = 0x01
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    66
FLAG_COMMAND_DATA_EOS = 0x02
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    67
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    68
FLAGS_COMMAND_DATA = {
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    69
    b'continuation': FLAG_COMMAND_DATA_CONTINUATION,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    70
    b'eos': FLAG_COMMAND_DATA_EOS,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    71
}
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    72
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    73
FLAG_BYTES_RESPONSE_CONTINUATION = 0x01
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    74
FLAG_BYTES_RESPONSE_EOS = 0x02
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    75
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    76
FLAGS_BYTES_RESPONSE = {
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    77
    b'continuation': FLAG_BYTES_RESPONSE_CONTINUATION,
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    78
    b'eos': FLAG_BYTES_RESPONSE_EOS,
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    79
}
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    80
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    81
FLAG_ERROR_RESPONSE_PROTOCOL = 0x01
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    82
FLAG_ERROR_RESPONSE_APPLICATION = 0x02
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    83
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    84
FLAGS_ERROR_RESPONSE = {
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    85
    b'protocol': FLAG_ERROR_RESPONSE_PROTOCOL,
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    86
    b'application': FLAG_ERROR_RESPONSE_APPLICATION,
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    87
}
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    88
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    89
# Maps frame types to their available flags.
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    90
FRAME_TYPE_FLAGS = {
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    91
    FRAME_TYPE_COMMAND_NAME: FLAGS_COMMAND,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    92
    FRAME_TYPE_COMMAND_ARGUMENT: FLAGS_COMMAND_ARGUMENT,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    93
    FRAME_TYPE_COMMAND_DATA: FLAGS_COMMAND_DATA,
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    94
    FRAME_TYPE_BYTES_RESPONSE: FLAGS_BYTES_RESPONSE,
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    95
    FRAME_TYPE_ERROR_RESPONSE: FLAGS_ERROR_RESPONSE,
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
    96
    FRAME_TYPE_TEXT_OUTPUT: {},
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    97
}
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    98
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    99
ARGUMENT_FRAME_HEADER = struct.Struct(r'<HH')
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   100
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   101
@attr.s(slots=True)
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   102
class frameheader(object):
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   103
    """Represents the data in a frame header."""
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   104
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   105
    length = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   106
    requestid = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   107
    typeid = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   108
    flags = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   109
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   110
@attr.s(slots=True)
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   111
class frame(object):
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   112
    """Represents a parsed frame."""
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   113
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   114
    requestid = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   115
    typeid = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   116
    flags = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   117
    payload = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   118
37065
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   119
def makeframe(requestid, typeid, flags, payload):
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   120
    """Assemble a frame into a byte array."""
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   121
    # TODO assert size of payload.
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   122
    frame = bytearray(FRAME_HEADER_SIZE + len(payload))
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   123
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   124
    # 24 bits length
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   125
    # 16 bits request id
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   126
    # 4 bits type
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   127
    # 4 bits flags
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   128
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   129
    l = struct.pack(r'<I', len(payload))
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   130
    frame[0:3] = l[0:3]
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   131
    struct.pack_into(r'<H', frame, 3, requestid)
37065
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   132
    frame[5] = (typeid << 4) | flags
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   133
    frame[6:] = payload
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   134
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   135
    return frame
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   136
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   137
def makeframefromhumanstring(s):
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   138
    """Create a frame from a human readable string
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   139
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   140
    Strings have the form:
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   141
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   142
        <request-id> <type> <flags> <payload>
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   143
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   144
    This can be used by user-facing applications and tests for creating
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   145
    frames easily without having to type out a bunch of constants.
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   146
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   147
    Request ID is an integer.
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   148
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   149
    Frame type and flags can be specified by integer or named constant.
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   150
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   151
    Flags can be delimited by `|` to bitwise OR them together.
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   152
    """
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   153
    requestid, frametype, frameflags, payload = s.split(b' ', 3)
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   154
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   155
    requestid = int(requestid)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   156
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   157
    if frametype in FRAME_TYPES:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   158
        frametype = FRAME_TYPES[frametype]
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   159
    else:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   160
        frametype = int(frametype)
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   161
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   162
    finalflags = 0
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   163
    validflags = FRAME_TYPE_FLAGS[frametype]
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   164
    for flag in frameflags.split(b'|'):
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   165
        if flag in validflags:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   166
            finalflags |= validflags[flag]
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   167
        else:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   168
            finalflags |= int(flag)
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   169
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37066
diff changeset
   170
    payload = stringutil.unescapestr(payload)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   171
37065
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   172
    return makeframe(requestid=requestid, typeid=frametype,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   173
                     flags=finalflags, payload=payload)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   174
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   175
def parseheader(data):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   176
    """Parse a unified framing protocol frame header from a buffer.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   177
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   178
    The header is expected to be in the buffer at offset 0 and the
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   179
    buffer is expected to be large enough to hold a full header.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   180
    """
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   181
    # 24 bits payload length (little endian)
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   182
    # 4 bits frame type
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   183
    # 4 bits frame flags
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   184
    # ... payload
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   185
    framelength = data[0] + 256 * data[1] + 16384 * data[2]
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   186
    requestid = struct.unpack_from(r'<H', data, 3)[0]
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   187
    typeflags = data[5]
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   188
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   189
    frametype = (typeflags & 0xf0) >> 4
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   190
    frameflags = typeflags & 0x0f
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   191
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   192
    return frameheader(framelength, requestid, frametype, frameflags)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   193
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   194
def readframe(fh):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   195
    """Read a unified framing protocol frame from a file object.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   196
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   197
    Returns a 3-tuple of (type, flags, payload) for the decoded frame or
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   198
    None if no frame is available. May raise if a malformed frame is
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   199
    seen.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   200
    """
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   201
    header = bytearray(FRAME_HEADER_SIZE)
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   202
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   203
    readcount = fh.readinto(header)
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   204
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   205
    if readcount == 0:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   206
        return None
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   207
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   208
    if readcount != FRAME_HEADER_SIZE:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   209
        raise error.Abort(_('received incomplete frame: got %d bytes: %s') %
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   210
                          (readcount, header))
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   211
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   212
    h = parseheader(header)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   213
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   214
    payload = fh.read(h.length)
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   215
    if len(payload) != h.length:
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   216
        raise error.Abort(_('frame length error: expected %d; got %d') %
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   217
                          (h.length, len(payload)))
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   218
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   219
    return frame(h.requestid, h.typeid, h.flags, payload)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   220
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   221
def createcommandframes(requestid, cmd, args, datafh=None):
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   222
    """Create frames necessary to transmit a request to run a command.
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   223
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   224
    This is a generator of bytearrays. Each item represents a frame
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   225
    ready to be sent over the wire to a peer.
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   226
    """
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   227
    flags = 0
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   228
    if args:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   229
        flags |= FLAG_COMMAND_NAME_HAVE_ARGS
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   230
    if datafh:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   231
        flags |= FLAG_COMMAND_NAME_HAVE_DATA
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   232
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   233
    if not flags:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   234
        flags |= FLAG_COMMAND_NAME_EOS
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   235
37065
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   236
    yield makeframe(requestid=requestid, typeid=FRAME_TYPE_COMMAND_NAME,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   237
                    flags=flags, payload=cmd)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   238
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   239
    for i, k in enumerate(sorted(args)):
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   240
        v = args[k]
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   241
        last = i == len(args) - 1
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   242
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   243
        # TODO handle splitting of argument values across frames.
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   244
        payload = bytearray(ARGUMENT_FRAME_HEADER.size + len(k) + len(v))
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   245
        offset = 0
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   246
        ARGUMENT_FRAME_HEADER.pack_into(payload, offset, len(k), len(v))
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   247
        offset += ARGUMENT_FRAME_HEADER.size
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   248
        payload[offset:offset + len(k)] = k
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   249
        offset += len(k)
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   250
        payload[offset:offset + len(v)] = v
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   251
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   252
        flags = FLAG_COMMAND_ARGUMENT_EOA if last else 0
37065
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   253
        yield makeframe(requestid=requestid,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   254
                        typeid=FRAME_TYPE_COMMAND_ARGUMENT,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   255
                        flags=flags,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   256
                        payload=payload)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   257
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   258
    if datafh:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   259
        while True:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   260
            data = datafh.read(DEFAULT_MAX_FRAME_SIZE)
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   261
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   262
            done = False
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   263
            if len(data) == DEFAULT_MAX_FRAME_SIZE:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   264
                flags = FLAG_COMMAND_DATA_CONTINUATION
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   265
            else:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   266
                flags = FLAG_COMMAND_DATA_EOS
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   267
                assert datafh.read(1) == b''
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   268
                done = True
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   269
37065
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   270
            yield makeframe(requestid=requestid,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   271
                            typeid=FRAME_TYPE_COMMAND_DATA,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   272
                            flags=flags,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   273
                            payload=data)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   274
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   275
            if done:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   276
                break
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   277
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   278
def createbytesresponseframesfrombytes(requestid, data,
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   279
                                       maxframesize=DEFAULT_MAX_FRAME_SIZE):
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   280
    """Create a raw frame to send a bytes response from static bytes input.
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   281
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   282
    Returns a generator of bytearrays.
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   283
    """
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   284
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   285
    # Simple case of a single frame.
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   286
    if len(data) <= maxframesize:
37065
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   287
        yield makeframe(requestid=requestid,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   288
                        typeid=FRAME_TYPE_BYTES_RESPONSE,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   289
                        flags=FLAG_BYTES_RESPONSE_EOS,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   290
                        payload=data)
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   291
        return
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   292
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   293
    offset = 0
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   294
    while True:
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   295
        chunk = data[offset:offset + maxframesize]
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   296
        offset += len(chunk)
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   297
        done = offset == len(data)
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   298
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   299
        if done:
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   300
            flags = FLAG_BYTES_RESPONSE_EOS
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   301
        else:
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   302
            flags = FLAG_BYTES_RESPONSE_CONTINUATION
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   303
37065
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   304
        yield makeframe(requestid=requestid,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   305
                        typeid=FRAME_TYPE_BYTES_RESPONSE,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   306
                        flags=flags,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   307
                        payload=chunk)
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   308
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   309
        if done:
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   310
            break
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   311
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   312
def createerrorframe(requestid, msg, protocol=False, application=False):
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   313
    # TODO properly handle frame size limits.
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   314
    assert len(msg) <= DEFAULT_MAX_FRAME_SIZE
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   315
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   316
    flags = 0
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   317
    if protocol:
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   318
        flags |= FLAG_ERROR_RESPONSE_PROTOCOL
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   319
    if application:
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   320
        flags |= FLAG_ERROR_RESPONSE_APPLICATION
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   321
37065
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   322
    yield makeframe(requestid=requestid,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   323
                    typeid=FRAME_TYPE_ERROR_RESPONSE,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   324
                    flags=flags,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   325
                    payload=msg)
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   326
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   327
def createtextoutputframe(requestid, atoms):
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   328
    """Create a text output frame to render text to people.
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   329
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   330
    ``atoms`` is a 3-tuple of (formatting string, args, labels).
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   331
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   332
    The formatting string contains ``%s`` tokens to be replaced by the
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   333
    corresponding indexed entry in ``args``. ``labels`` is an iterable of
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   334
    formatters to be applied at rendering time. In terms of the ``ui``
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   335
    class, each atom corresponds to a ``ui.write()``.
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   336
    """
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   337
    bytesleft = DEFAULT_MAX_FRAME_SIZE
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   338
    atomchunks = []
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   339
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   340
    for (formatting, args, labels) in atoms:
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   341
        if len(args) > 255:
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   342
            raise ValueError('cannot use more than 255 formatting arguments')
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   343
        if len(labels) > 255:
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   344
            raise ValueError('cannot use more than 255 labels')
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   345
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   346
        # TODO look for localstr, other types here?
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   347
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   348
        if not isinstance(formatting, bytes):
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   349
            raise ValueError('must use bytes formatting strings')
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   350
        for arg in args:
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   351
            if not isinstance(arg, bytes):
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   352
                raise ValueError('must use bytes for arguments')
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   353
        for label in labels:
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   354
            if not isinstance(label, bytes):
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   355
                raise ValueError('must use bytes for labels')
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   356
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   357
        # Formatting string must be UTF-8.
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   358
        formatting = formatting.decode(r'utf-8', r'replace').encode(r'utf-8')
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   359
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   360
        # Arguments must be UTF-8.
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   361
        args = [a.decode(r'utf-8', r'replace').encode(r'utf-8') for a in args]
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   362
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   363
        # Labels must be ASCII.
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   364
        labels = [l.decode(r'ascii', r'strict').encode(r'ascii')
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   365
                  for l in labels]
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   366
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   367
        if len(formatting) > 65535:
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   368
            raise ValueError('formatting string cannot be longer than 64k')
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   369
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   370
        if any(len(a) > 65535 for a in args):
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   371
            raise ValueError('argument string cannot be longer than 64k')
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   372
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   373
        if any(len(l) > 255 for l in labels):
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   374
            raise ValueError('label string cannot be longer than 255 bytes')
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   375
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   376
        chunks = [
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   377
            struct.pack(r'<H', len(formatting)),
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   378
            struct.pack(r'<BB', len(labels), len(args)),
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   379
            struct.pack(r'<' + r'B' * len(labels), *map(len, labels)),
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   380
            struct.pack(r'<' + r'H' * len(args), *map(len, args)),
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   381
        ]
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   382
        chunks.append(formatting)
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   383
        chunks.extend(labels)
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   384
        chunks.extend(args)
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   385
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   386
        atom = b''.join(chunks)
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   387
        atomchunks.append(atom)
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   388
        bytesleft -= len(atom)
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   389
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   390
    if bytesleft < 0:
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   391
        raise ValueError('cannot encode data in a single frame')
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   392
37065
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   393
    yield makeframe(requestid=requestid,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   394
                    typeid=FRAME_TYPE_TEXT_OUTPUT,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   395
                    flags=0,
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   396
                    payload=b''.join(atomchunks))
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   397
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   398
class serverreactor(object):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   399
    """Holds state of a server handling frame-based protocol requests.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   400
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   401
    This class is the "brain" of the unified frame-based protocol server
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   402
    component. While the protocol is stateless from the perspective of
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   403
    requests/commands, something needs to track which frames have been
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   404
    received, what frames to expect, etc. This class is that thing.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   405
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   406
    Instances are modeled as a state machine of sorts. Instances are also
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   407
    reactionary to external events. The point of this class is to encapsulate
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   408
    the state of the connection and the exchange of frames, not to perform
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   409
    work. Instead, callers tell this class when something occurs, like a
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   410
    frame arriving. If that activity is worthy of a follow-up action (say
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   411
    *run a command*), the return value of that handler will say so.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   412
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   413
    I/O and CPU intensive operations are purposefully delegated outside of
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   414
    this class.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   415
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   416
    Consumers are expected to tell instances when events occur. They do so by
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   417
    calling the various ``on*`` methods. These methods return a 2-tuple
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   418
    describing any follow-up action(s) to take. The first element is the
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   419
    name of an action to perform. The second is a data structure (usually
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   420
    a dict) specific to that action that contains more information. e.g.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   421
    if the server wants to send frames back to the client, the data structure
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   422
    will contain a reference to those frames.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   423
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   424
    Valid actions that consumers can be instructed to take are:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   425
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   426
    sendframes
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   427
       Indicates that frames should be sent to the client. The ``framegen``
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   428
       key contains a generator of frames that should be sent. The server
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   429
       assumes that all frames are sent to the client.
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   430
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   431
    error
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   432
       Indicates that an error occurred. Consumer should probably abort.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   433
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   434
    runcommand
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   435
       Indicates that the consumer should run a wire protocol command. Details
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   436
       of the command to run are given in the data structure.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   437
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   438
    wantframe
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   439
       Indicates that nothing of interest happened and the server is waiting on
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   440
       more frames from the client before anything interesting can be done.
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   441
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   442
    noop
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   443
       Indicates no additional action is required.
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   444
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   445
    Known Issues
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   446
    ------------
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   447
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   448
    There are no limits to the number of partially received commands or their
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   449
    size. A malicious client could stream command request data and exhaust the
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   450
    server's memory.
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   451
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   452
    Partially received commands are not acted upon when end of input is
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   453
    reached. Should the server error if it receives a partial request?
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   454
    Should the client send a message to abort a partially transmitted request
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   455
    to facilitate graceful shutdown?
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   456
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   457
    Active requests that haven't been responded to aren't tracked. This means
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   458
    that if we receive a command and instruct its dispatch, another command
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   459
    with its request ID can come in over the wire and there will be a race
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   460
    between who responds to what.
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   461
    """
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   462
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   463
    def __init__(self, deferoutput=False):
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   464
        """Construct a new server reactor.
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   465
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   466
        ``deferoutput`` can be used to indicate that no output frames should be
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   467
        instructed to be sent until input has been exhausted. In this mode,
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   468
        events that would normally generate output frames (such as a command
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   469
        response being ready) will instead defer instructing the consumer to
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   470
        send those frames. This is useful for half-duplex transports where the
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   471
        sender cannot receive until all data has been transmitted.
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   472
        """
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   473
        self._deferoutput = deferoutput
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   474
        self._state = 'idle'
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   475
        self._bufferedframegens = []
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   476
        # request id -> dict of commands that are actively being received.
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   477
        self._receivingcommands = {}
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   478
        # Request IDs that have been received and are actively being processed.
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   479
        # Once all output for a request has been sent, it is removed from this
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   480
        # set.
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   481
        self._activecommands = set()
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   482
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   483
    def onframerecv(self, frame):
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   484
        """Process a frame that has been received off the wire.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   485
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   486
        Returns a dict with an ``action`` key that details what action,
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   487
        if any, the consumer should take next.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   488
        """
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   489
        handlers = {
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   490
            'idle': self._onframeidle,
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   491
            'command-receiving': self._onframecommandreceiving,
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   492
            'errored': self._onframeerrored,
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   493
        }
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   494
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   495
        meth = handlers.get(self._state)
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   496
        if not meth:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   497
            raise error.ProgrammingError('unhandled state: %s' % self._state)
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   498
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   499
        return meth(frame)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   500
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   501
    def onbytesresponseready(self, requestid, data):
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   502
        """Signal that a bytes response is ready to be sent to the client.
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   503
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   504
        The raw bytes response is passed as an argument.
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   505
        """
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   506
        def sendframes():
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   507
            for frame in createbytesresponseframesfrombytes(requestid, data):
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   508
                yield frame
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   509
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   510
            self._activecommands.remove(requestid)
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   511
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   512
        result = sendframes()
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   513
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   514
        if self._deferoutput:
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   515
            self._bufferedframegens.append(result)
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   516
            return 'noop', {}
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   517
        else:
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   518
            return 'sendframes', {
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   519
                'framegen': result,
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   520
            }
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   521
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   522
    def oninputeof(self):
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   523
        """Signals that end of input has been received.
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   524
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   525
        No more frames will be received. All pending activity should be
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   526
        completed.
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   527
        """
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   528
        # TODO should we do anything about in-flight commands?
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   529
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   530
        if not self._deferoutput or not self._bufferedframegens:
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   531
            return 'noop', {}
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   532
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   533
        # If we buffered all our responses, emit those.
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   534
        def makegen():
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   535
            for gen in self._bufferedframegens:
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   536
                for frame in gen:
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   537
                    yield frame
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   538
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   539
        return 'sendframes', {
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   540
            'framegen': makegen(),
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   541
        }
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   542
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   543
    def onapplicationerror(self, requestid, msg):
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   544
        return 'sendframes', {
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   545
            'framegen': createerrorframe(requestid, msg, application=True),
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   546
        }
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   547
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   548
    def _makeerrorresult(self, msg):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   549
        return 'error', {
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   550
            'message': msg,
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   551
        }
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   552
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   553
    def _makeruncommandresult(self, requestid):
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   554
        entry = self._receivingcommands[requestid]
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   555
        del self._receivingcommands[requestid]
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   556
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   557
        if self._receivingcommands:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   558
            self._state = 'command-receiving'
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   559
        else:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   560
            self._state = 'idle'
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   561
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   562
        assert requestid not in self._activecommands
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   563
        self._activecommands.add(requestid)
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   564
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   565
        return 'runcommand', {
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   566
            'requestid': requestid,
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   567
            'command': entry['command'],
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   568
            'args': entry['args'],
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   569
            'data': entry['data'].getvalue() if entry['data'] else None,
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   570
        }
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   571
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   572
    def _makewantframeresult(self):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   573
        return 'wantframe', {
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   574
            'state': self._state,
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   575
        }
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   576
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   577
    def _onframeidle(self, frame):
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   578
        # The only frame type that should be received in this state is a
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   579
        # command request.
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   580
        if frame.typeid != FRAME_TYPE_COMMAND_NAME:
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   581
            self._state = 'errored'
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   582
            return self._makeerrorresult(
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   583
                _('expected command frame; got %d') % frame.typeid)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   584
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   585
        if frame.requestid in self._receivingcommands:
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   586
            self._state = 'errored'
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   587
            return self._makeerrorresult(
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   588
                _('request with ID %d already received') % frame.requestid)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   589
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   590
        if frame.requestid in self._activecommands:
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   591
            self._state = 'errored'
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   592
            return self._makeerrorresult((
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   593
                _('request with ID %d is already active') % frame.requestid))
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   594
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   595
        expectingargs = bool(frame.flags & FLAG_COMMAND_NAME_HAVE_ARGS)
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   596
        expectingdata = bool(frame.flags & FLAG_COMMAND_NAME_HAVE_DATA)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   597
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   598
        self._receivingcommands[frame.requestid] = {
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   599
            'command': frame.payload,
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   600
            'args': {},
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   601
            'data': None,
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   602
            'expectingargs': expectingargs,
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   603
            'expectingdata': expectingdata,
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   604
        }
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   605
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   606
        if frame.flags & FLAG_COMMAND_NAME_EOS:
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   607
            return self._makeruncommandresult(frame.requestid)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   608
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   609
        if expectingargs or expectingdata:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   610
            self._state = 'command-receiving'
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   611
            return self._makewantframeresult()
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   612
        else:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   613
            self._state = 'errored'
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   614
            return self._makeerrorresult(_('missing frame flags on '
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   615
                                           'command frame'))
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   616
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   617
    def _onframecommandreceiving(self, frame):
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   618
        # It could be a new command request. Process it as such.
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   619
        if frame.typeid == FRAME_TYPE_COMMAND_NAME:
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   620
            return self._onframeidle(frame)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   621
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   622
        # All other frames should be related to a command that is currently
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   623
        # receiving but is not active.
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   624
        if frame.requestid in self._activecommands:
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   625
            self._state = 'errored'
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   626
            return self._makeerrorresult(
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   627
                _('received frame for request that is still active: %d') %
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   628
                frame.requestid)
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   629
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   630
        if frame.requestid not in self._receivingcommands:
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   631
            self._state = 'errored'
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   632
            return self._makeerrorresult(
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   633
                _('received frame for request that is not receiving: %d') %
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   634
                  frame.requestid)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   635
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   636
        entry = self._receivingcommands[frame.requestid]
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   637
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   638
        if frame.typeid == FRAME_TYPE_COMMAND_ARGUMENT:
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   639
            if not entry['expectingargs']:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   640
                self._state = 'errored'
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   641
                return self._makeerrorresult(_(
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   642
                    'received command argument frame for request that is not '
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   643
                    'expecting arguments: %d') % frame.requestid)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   644
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   645
            return self._handlecommandargsframe(frame, entry)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   646
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   647
        elif frame.typeid == FRAME_TYPE_COMMAND_DATA:
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   648
            if not entry['expectingdata']:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   649
                self._state = 'errored'
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   650
                return self._makeerrorresult(_(
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   651
                    'received command data frame for request that is not '
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   652
                    'expecting data: %d') % frame.requestid)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   653
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   654
            if entry['data'] is None:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   655
                entry['data'] = util.bytesio()
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   656
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   657
            return self._handlecommanddataframe(frame, entry)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   658
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   659
    def _handlecommandargsframe(self, frame, entry):
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   660
        # The frame and state of command should have already been validated.
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   661
        assert frame.typeid == FRAME_TYPE_COMMAND_ARGUMENT
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   662
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   663
        offset = 0
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   664
        namesize, valuesize = ARGUMENT_FRAME_HEADER.unpack_from(frame.payload)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   665
        offset += ARGUMENT_FRAME_HEADER.size
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   666
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   667
        # The argument name MUST fit inside the frame.
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   668
        argname = bytes(frame.payload[offset:offset + namesize])
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   669
        offset += namesize
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   670
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   671
        if len(argname) != namesize:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   672
            self._state = 'errored'
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   673
            return self._makeerrorresult(_('malformed argument frame: '
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   674
                                           'partial argument name'))
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   675
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   676
        argvalue = bytes(frame.payload[offset:])
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   677
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   678
        # Argument value spans multiple frames. Record our active state
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   679
        # and wait for the next frame.
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   680
        if frame.flags & FLAG_COMMAND_ARGUMENT_CONTINUATION:
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   681
            raise error.ProgrammingError('not yet implemented')
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   682
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   683
        # Common case: the argument value is completely contained in this
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   684
        # frame.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   685
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   686
        if len(argvalue) != valuesize:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   687
            self._state = 'errored'
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   688
            return self._makeerrorresult(_('malformed argument frame: '
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   689
                                           'partial argument value'))
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   690
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   691
        entry['args'][argname] = argvalue
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   692
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   693
        if frame.flags & FLAG_COMMAND_ARGUMENT_EOA:
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   694
            if entry['expectingdata']:
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   695
                # TODO signal request to run a command once we don't
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   696
                # buffer data frames.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   697
                return self._makewantframeresult()
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   698
            else:
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   699
                return self._makeruncommandresult(frame.requestid)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   700
        else:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   701
            return self._makewantframeresult()
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   702
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   703
    def _handlecommanddataframe(self, frame, entry):
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   704
        assert frame.typeid == FRAME_TYPE_COMMAND_DATA
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   705
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   706
        # TODO support streaming data instead of buffering it.
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   707
        entry['data'].write(frame.payload)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   708
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   709
        if frame.flags & FLAG_COMMAND_DATA_CONTINUATION:
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   710
            return self._makewantframeresult()
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   711
        elif frame.flags & FLAG_COMMAND_DATA_EOS:
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   712
            entry['data'].seek(0)
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   713
            return self._makeruncommandresult(frame.requestid)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   714
        else:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   715
            self._state = 'errored'
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   716
            return self._makeerrorresult(_('command data frame without '
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   717
                                           'flags'))
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   718
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   719
    def _onframeerrored(self, frame):
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   720
        return self._makeerrorresult(_('server already errored'))