mercurial/wireprotoframing.py
author Pierre-Yves David <pierre-yves.david@octobus.net>
Wed, 07 Aug 2019 20:09:10 +0200
changeset 42786 af9c591216ea
parent 40328 2c55716f8a1c
child 43076 2372284d9457
permissions -rw-r--r--
rawdata: update callers in bundlerepo We update callers incrementally because this help bisecting failures. This was useful during development, so we expect it might be useful again in the future.
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
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
    14
import collections
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    15
import struct
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    16
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
    17
from .i18n import _
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
    18
from .thirdparty import (
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
    19
    attr,
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
    20
)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    21
from . import (
37474
d33997123ea5 py3: system-stringify repr(frame)
Yuya Nishihara <yuya@tcha.org>
parents: 37473
diff changeset
    22
    encoding,
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
    23
    error,
40026
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
    24
    pycompat,
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    25
    util,
40021
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
    26
    wireprototypes,
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    27
)
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37066
diff changeset
    28
from .utils import (
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
    29
    cborutil,
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37066
diff changeset
    30
    stringutil,
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37066
diff changeset
    31
)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    32
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
    33
FRAME_HEADER_SIZE = 8
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    34
DEFAULT_MAX_FRAME_SIZE = 32768
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    35
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
    36
STREAM_FLAG_BEGIN_STREAM = 0x01
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
    37
STREAM_FLAG_END_STREAM = 0x02
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
    38
STREAM_FLAG_ENCODING_APPLIED = 0x04
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
    39
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
    40
STREAM_FLAGS = {
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
    41
    b'stream-begin': STREAM_FLAG_BEGIN_STREAM,
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
    42
    b'stream-end': STREAM_FLAG_END_STREAM,
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
    43
    b'encoded': STREAM_FLAG_ENCODING_APPLIED,
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
    44
}
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
    45
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
    46
FRAME_TYPE_COMMAND_REQUEST = 0x01
37723
e8fba6d578f0 wireprotov2: change frame type value for command data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
    47
FRAME_TYPE_COMMAND_DATA = 0x02
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
    48
FRAME_TYPE_COMMAND_RESPONSE = 0x03
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    49
FRAME_TYPE_ERROR_RESPONSE = 0x05
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
    50
FRAME_TYPE_TEXT_OUTPUT = 0x06
37291
b0041036214e wireproto: define frame to represent progress updates
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37290
diff changeset
    51
FRAME_TYPE_PROGRESS = 0x07
40126
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
    52
FRAME_TYPE_SENDER_PROTOCOL_SETTINGS = 0x08
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
    53
FRAME_TYPE_STREAM_SETTINGS = 0x09
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    54
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    55
FRAME_TYPES = {
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
    56
    b'command-request': FRAME_TYPE_COMMAND_REQUEST,
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    57
    b'command-data': FRAME_TYPE_COMMAND_DATA,
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
    58
    b'command-response': FRAME_TYPE_COMMAND_RESPONSE,
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    59
    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
    60
    b'text-output': FRAME_TYPE_TEXT_OUTPUT,
37291
b0041036214e wireproto: define frame to represent progress updates
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37290
diff changeset
    61
    b'progress': FRAME_TYPE_PROGRESS,
40126
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
    62
    b'sender-protocol-settings': FRAME_TYPE_SENDER_PROTOCOL_SETTINGS,
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
    63
    b'stream-settings': FRAME_TYPE_STREAM_SETTINGS,
37054
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
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
    66
FLAG_COMMAND_REQUEST_NEW = 0x01
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
    67
FLAG_COMMAND_REQUEST_CONTINUATION = 0x02
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
    68
FLAG_COMMAND_REQUEST_MORE_FRAMES = 0x04
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
    69
FLAG_COMMAND_REQUEST_EXPECT_DATA = 0x08
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    70
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
    71
FLAGS_COMMAND_REQUEST = {
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
    72
    b'new': FLAG_COMMAND_REQUEST_NEW,
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
    73
    b'continuation': FLAG_COMMAND_REQUEST_CONTINUATION,
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
    74
    b'more': FLAG_COMMAND_REQUEST_MORE_FRAMES,
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
    75
    b'have-data': FLAG_COMMAND_REQUEST_EXPECT_DATA,
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    76
}
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    77
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    78
FLAG_COMMAND_DATA_CONTINUATION = 0x01
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    79
FLAG_COMMAND_DATA_EOS = 0x02
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    80
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    81
FLAGS_COMMAND_DATA = {
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    82
    b'continuation': FLAG_COMMAND_DATA_CONTINUATION,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    83
    b'eos': FLAG_COMMAND_DATA_EOS,
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    84
}
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    85
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
    86
FLAG_COMMAND_RESPONSE_CONTINUATION = 0x01
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
    87
FLAG_COMMAND_RESPONSE_EOS = 0x02
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    88
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
    89
FLAGS_COMMAND_RESPONSE = {
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
    90
    b'continuation': FLAG_COMMAND_RESPONSE_CONTINUATION,
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
    91
    b'eos': FLAG_COMMAND_RESPONSE_EOS,
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    92
}
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
    93
40126
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
    94
FLAG_SENDER_PROTOCOL_SETTINGS_CONTINUATION = 0x01
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
    95
FLAG_SENDER_PROTOCOL_SETTINGS_EOS = 0x02
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
    96
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
    97
FLAGS_SENDER_PROTOCOL_SETTINGS = {
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
    98
    b'continuation': FLAG_SENDER_PROTOCOL_SETTINGS_CONTINUATION,
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
    99
    b'eos': FLAG_SENDER_PROTOCOL_SETTINGS_EOS,
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
   100
}
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
   101
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
   102
FLAG_STREAM_ENCODING_SETTINGS_CONTINUATION = 0x01
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
   103
FLAG_STREAM_ENCODING_SETTINGS_EOS = 0x02
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
   104
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
   105
FLAGS_STREAM_ENCODING_SETTINGS = {
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
   106
    b'continuation': FLAG_STREAM_ENCODING_SETTINGS_CONTINUATION,
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
   107
    b'eos': FLAG_STREAM_ENCODING_SETTINGS_EOS,
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
   108
}
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
   109
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   110
# 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
   111
FRAME_TYPE_FLAGS = {
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   112
    FRAME_TYPE_COMMAND_REQUEST: FLAGS_COMMAND_REQUEST,
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   113
    FRAME_TYPE_COMMAND_DATA: FLAGS_COMMAND_DATA,
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
   114
    FRAME_TYPE_COMMAND_RESPONSE: FLAGS_COMMAND_RESPONSE,
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
   115
    FRAME_TYPE_ERROR_RESPONSE: {},
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   116
    FRAME_TYPE_TEXT_OUTPUT: {},
37291
b0041036214e wireproto: define frame to represent progress updates
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37290
diff changeset
   117
    FRAME_TYPE_PROGRESS: {},
40126
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
   118
    FRAME_TYPE_SENDER_PROTOCOL_SETTINGS: FLAGS_SENDER_PROTOCOL_SETTINGS,
e2fe1074024c wireprotov2: update stream encoding specification
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40026
diff changeset
   119
    FRAME_TYPE_STREAM_SETTINGS: FLAGS_STREAM_ENCODING_SETTINGS,
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   120
}
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   121
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   122
ARGUMENT_RECORD_HEADER = struct.Struct(r'<HH')
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   123
37298
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   124
def humanflags(mapping, value):
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   125
    """Convert a numeric flags value to a human value, using a mapping table."""
37473
7c2c7c749411 wireproto: show unknown id and flags in repr(frame)
Yuya Nishihara <yuya@tcha.org>
parents: 37472
diff changeset
   126
    namemap = {v: k for k, v in mapping.iteritems()}
37298
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   127
    flags = []
37473
7c2c7c749411 wireproto: show unknown id and flags in repr(frame)
Yuya Nishihara <yuya@tcha.org>
parents: 37472
diff changeset
   128
    val = 1
7c2c7c749411 wireproto: show unknown id and flags in repr(frame)
Yuya Nishihara <yuya@tcha.org>
parents: 37472
diff changeset
   129
    while value >= val:
37298
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   130
        if value & val:
37473
7c2c7c749411 wireproto: show unknown id and flags in repr(frame)
Yuya Nishihara <yuya@tcha.org>
parents: 37472
diff changeset
   131
            flags.append(namemap.get(val, '<unknown 0x%02x>' % val))
7c2c7c749411 wireproto: show unknown id and flags in repr(frame)
Yuya Nishihara <yuya@tcha.org>
parents: 37472
diff changeset
   132
        val <<= 1
37298
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   133
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   134
    return b'|'.join(flags)
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   135
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   136
@attr.s(slots=True)
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   137
class frameheader(object):
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   138
    """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
   139
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   140
    length = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   141
    requestid = attr.ib()
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   142
    streamid = attr.ib()
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   143
    streamflags = attr.ib()
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   144
    typeid = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   145
    flags = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   146
37298
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   147
@attr.s(slots=True, repr=False)
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   148
class frame(object):
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   149
    """Represents a parsed frame."""
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   150
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   151
    requestid = attr.ib()
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   152
    streamid = attr.ib()
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   153
    streamflags = attr.ib()
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   154
    typeid = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   155
    flags = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   156
    payload = attr.ib()
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   157
37474
d33997123ea5 py3: system-stringify repr(frame)
Yuya Nishihara <yuya@tcha.org>
parents: 37473
diff changeset
   158
    @encoding.strmethod
37298
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   159
    def __repr__(self):
37473
7c2c7c749411 wireproto: show unknown id and flags in repr(frame)
Yuya Nishihara <yuya@tcha.org>
parents: 37472
diff changeset
   160
        typename = '<unknown 0x%02x>' % self.typeid
37298
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   161
        for name, value in FRAME_TYPES.iteritems():
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   162
            if value == self.typeid:
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   163
                typename = name
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   164
                break
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   165
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   166
        return ('frame(size=%d; request=%d; stream=%d; streamflags=%s; '
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   167
                'type=%s; flags=%s)' % (
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   168
            len(self.payload), self.requestid, self.streamid,
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   169
            humanflags(STREAM_FLAGS, self.streamflags), typename,
37472
2f81926c7f89 wireproto: fix repr(frame) to not crash by unknown type id
Yuya Nishihara <yuya@tcha.org>
parents: 37319
diff changeset
   170
            humanflags(FRAME_TYPE_FLAGS.get(self.typeid, {}), self.flags)))
37298
5ef2da00e935 wireproto: implement custom __repr__ for frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
   171
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   172
def makeframe(requestid, streamid, streamflags, typeid, flags, payload):
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   173
    """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
   174
    # TODO assert size of payload.
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   175
    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
   176
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   177
    # 24 bits length
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   178
    # 16 bits request id
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   179
    # 8 bits stream id
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   180
    # 8 bits stream flags
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   181
    # 4 bits type
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   182
    # 4 bits flags
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   183
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   184
    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
   185
    frame[0:3] = l[0:3]
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   186
    struct.pack_into(r'<HBB', frame, 3, requestid, streamid, streamflags)
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   187
    frame[7] = (typeid << 4) | flags
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   188
    frame[8:] = payload
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   189
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   190
    return frame
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   191
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   192
def makeframefromhumanstring(s):
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   193
    """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
   194
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   195
    Strings have the form:
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   196
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   197
        <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   198
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   199
    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
   200
    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
   201
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   202
    Request ID and stream IDs are integers.
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   203
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   204
    Stream flags, frame type, and flags can be specified by integer or
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   205
    named constant.
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   206
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   207
    Flags can be delimited by `|` to bitwise OR them together.
37290
cc5a040fe150 wireproto: syntax for encoding CBOR into frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37289
diff changeset
   208
cc5a040fe150 wireproto: syntax for encoding CBOR into frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37289
diff changeset
   209
    If the payload begins with ``cbor:``, the following string will be
37476
e9dea82ea1f3 wireproto: convert python literal to object without using unsafe eval()
Yuya Nishihara <yuya@tcha.org>
parents: 37474
diff changeset
   210
    evaluated as Python literal and the resulting object will be fed into
37290
cc5a040fe150 wireproto: syntax for encoding CBOR into frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37289
diff changeset
   211
    a CBOR encoder. Otherwise, the payload is interpreted as a Python
cc5a040fe150 wireproto: syntax for encoding CBOR into frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37289
diff changeset
   212
    byte string literal.
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   213
    """
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   214
    fields = s.split(b' ', 5)
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   215
    requestid, streamid, streamflags, frametype, frameflags, payload = fields
37060
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   216
2ec1fb9de638 wireproto: add request IDs to frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37059
diff changeset
   217
    requestid = int(requestid)
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   218
    streamid = int(streamid)
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   219
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   220
    finalstreamflags = 0
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   221
    for flag in streamflags.split(b'|'):
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   222
        if flag in STREAM_FLAGS:
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   223
            finalstreamflags |= STREAM_FLAGS[flag]
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   224
        else:
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   225
            finalstreamflags |= int(flag)
37054
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
    if frametype in FRAME_TYPES:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   228
        frametype = FRAME_TYPES[frametype]
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   229
    else:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   230
        frametype = int(frametype)
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   231
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   232
    finalflags = 0
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   233
    validflags = FRAME_TYPE_FLAGS[frametype]
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   234
    for flag in frameflags.split(b'|'):
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   235
        if flag in validflags:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   236
            finalflags |= validflags[flag]
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   237
        else:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   238
            finalflags |= int(flag)
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   239
37290
cc5a040fe150 wireproto: syntax for encoding CBOR into frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37289
diff changeset
   240
    if payload.startswith(b'cbor:'):
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
   241
        payload = b''.join(cborutil.streamencode(
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
   242
            stringutil.evalpythonliteral(payload[5:])))
37290
cc5a040fe150 wireproto: syntax for encoding CBOR into frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37289
diff changeset
   243
cc5a040fe150 wireproto: syntax for encoding CBOR into frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37289
diff changeset
   244
    else:
cc5a040fe150 wireproto: syntax for encoding CBOR into frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37289
diff changeset
   245
        payload = stringutil.unescapestr(payload)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   246
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   247
    return makeframe(requestid=requestid, streamid=streamid,
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   248
                     streamflags=finalstreamflags, typeid=frametype,
37065
fe4c944f95bb wireproto: use named arguments when passing around frame data
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37064
diff changeset
   249
                     flags=finalflags, payload=payload)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   250
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   251
def parseheader(data):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   252
    """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
   253
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   254
    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
   255
    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
   256
    """
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   257
    # 24 bits payload length (little endian)
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   258
    # 16 bits request ID
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   259
    # 8 bits stream ID
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   260
    # 8 bits stream flags
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   261
    # 4 bits frame type
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   262
    # 4 bits frame flags
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   263
    # ... payload
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   264
    framelength = data[0] + 256 * data[1] + 16384 * data[2]
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   265
    requestid, streamid, streamflags = struct.unpack_from(r'<HBB', data, 3)
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   266
    typeflags = data[7]
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   267
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   268
    frametype = (typeflags & 0xf0) >> 4
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   269
    frameflags = typeflags & 0x0f
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   270
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   271
    return frameheader(framelength, requestid, streamid, streamflags,
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   272
                       frametype, frameflags)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   273
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   274
def readframe(fh):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   275
    """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
   276
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   277
    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
   278
    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
   279
    seen.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   280
    """
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   281
    header = bytearray(FRAME_HEADER_SIZE)
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   282
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   283
    readcount = fh.readinto(header)
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   284
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   285
    if readcount == 0:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   286
        return None
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   287
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   288
    if readcount != FRAME_HEADER_SIZE:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   289
        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
   290
                          (readcount, header))
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   291
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   292
    h = parseheader(header)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   293
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   294
    payload = fh.read(h.length)
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
   295
    if len(payload) != h.length:
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   296
        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
   297
                          (h.length, len(payload)))
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   298
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   299
    return frame(h.requestid, h.streamid, h.streamflags, h.typeid, h.flags,
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   300
                 payload)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   301
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   302
def createcommandframes(stream, requestid, cmd, args, datafh=None,
40025
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
   303
                        maxframesize=DEFAULT_MAX_FRAME_SIZE,
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
   304
                        redirect=None):
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   305
    """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
   306
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   307
    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
   308
    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
   309
    """
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   310
    data = {b'name': cmd}
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   311
    if args:
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   312
        data[b'args'] = args
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   313
40025
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
   314
    if redirect:
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
   315
        data[b'redirect'] = redirect
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
   316
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
   317
    data = b''.join(cborutil.streamencode(data))
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   318
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   319
    offset = 0
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   320
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   321
    while True:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   322
        flags = 0
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   323
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   324
        # Must set new or continuation flag.
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   325
        if not offset:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   326
            flags |= FLAG_COMMAND_REQUEST_NEW
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   327
        else:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   328
            flags |= FLAG_COMMAND_REQUEST_CONTINUATION
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   329
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   330
        # Data frames is set on all frames.
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   331
        if datafh:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   332
            flags |= FLAG_COMMAND_REQUEST_EXPECT_DATA
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   333
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   334
        payload = data[offset:offset + maxframesize]
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   335
        offset += len(payload)
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   336
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   337
        if len(payload) == maxframesize and offset < len(data):
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   338
            flags |= FLAG_COMMAND_REQUEST_MORE_FRAMES
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   339
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   340
        yield stream.makeframe(requestid=requestid,
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   341
                               typeid=FRAME_TYPE_COMMAND_REQUEST,
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   342
                               flags=flags,
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   343
                               payload=payload)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   344
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   345
        if not (flags & FLAG_COMMAND_REQUEST_MORE_FRAMES):
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   346
            break
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
   347
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   348
    if datafh:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   349
        while True:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   350
            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
   351
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   352
            done = False
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   353
            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
   354
                flags = FLAG_COMMAND_DATA_CONTINUATION
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   355
            else:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   356
                flags = FLAG_COMMAND_DATA_EOS
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   357
                assert datafh.read(1) == b''
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   358
                done = True
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   359
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   360
            yield stream.makeframe(requestid=requestid,
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   361
                                   typeid=FRAME_TYPE_COMMAND_DATA,
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   362
                                   flags=flags,
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   363
                                   payload=data)
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   364
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   365
            if done:
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   366
                break
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   367
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
   368
def createcommandresponseokframe(stream, requestid):
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
   369
    overall = b''.join(cborutil.streamencode({b'status': b'ok'}))
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
   370
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   371
    if stream.streamsettingssent:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   372
        overall = stream.encode(overall)
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   373
        encoded = True
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   374
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   375
        if not overall:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   376
            return None
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   377
    else:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   378
        encoded = False
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   379
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
   380
    return stream.makeframe(requestid=requestid,
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
   381
                            typeid=FRAME_TYPE_COMMAND_RESPONSE,
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
   382
                            flags=FLAG_COMMAND_RESPONSE_CONTINUATION,
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   383
                            payload=overall,
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   384
                            encoded=encoded)
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
   385
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   386
def createcommandresponseeosframes(stream, requestid,
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   387
                                   maxframesize=DEFAULT_MAX_FRAME_SIZE):
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
   388
    """Create an empty payload frame representing command end-of-stream."""
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   389
    payload = stream.flush()
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   390
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   391
    offset = 0
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   392
    while True:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   393
        chunk = payload[offset:offset + maxframesize]
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   394
        offset += len(chunk)
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   395
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   396
        done = offset == len(payload)
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   397
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   398
        if done:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   399
            flags = FLAG_COMMAND_RESPONSE_EOS
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   400
        else:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   401
            flags = FLAG_COMMAND_RESPONSE_CONTINUATION
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   402
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   403
        yield stream.makeframe(requestid=requestid,
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   404
                               typeid=FRAME_TYPE_COMMAND_RESPONSE,
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   405
                               flags=flags,
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   406
                               payload=chunk,
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   407
                               encoded=payload != b'')
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   408
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   409
        if done:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   410
            break
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   411
40026
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   412
def createalternatelocationresponseframe(stream, requestid, location):
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   413
    data = {
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   414
        b'status': b'redirect',
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   415
        b'location': {
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   416
            b'url': location.url,
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   417
            b'mediatype': location.mediatype,
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   418
        }
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   419
    }
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   420
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   421
    for a in (r'size', r'fullhashes', r'fullhashseed', r'serverdercerts',
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   422
              r'servercadercerts'):
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   423
        value = getattr(location, a)
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   424
        if value is not None:
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   425
            data[b'location'][pycompat.bytestr(a)] = value
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   426
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   427
    payload = b''.join(cborutil.streamencode(data))
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   428
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   429
    if stream.streamsettingssent:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   430
        payload = stream.encode(payload)
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   431
        encoded = True
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   432
    else:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   433
        encoded = False
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   434
40026
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   435
    return stream.makeframe(requestid=requestid,
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   436
                            typeid=FRAME_TYPE_COMMAND_RESPONSE,
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   437
                            flags=FLAG_COMMAND_RESPONSE_CONTINUATION,
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   438
                            payload=payload,
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   439
                            encoded=encoded)
40026
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
   440
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   441
def createcommanderrorresponse(stream, requestid, message, args=None):
39503
43d92d68ac88 wireprotov2peer: properly format errors
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39465
diff changeset
   442
    # TODO should this be using a list of {'msg': ..., 'args': {}} so atom
43d92d68ac88 wireprotov2peer: properly format errors
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39465
diff changeset
   443
    # formatting works consistently?
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   444
    m = {
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   445
        b'status': b'error',
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   446
        b'error': {
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   447
            b'message': message,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   448
        }
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   449
    }
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   450
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   451
    if args:
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   452
        m[b'error'][b'args'] = args
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   453
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
   454
    overall = b''.join(cborutil.streamencode(m))
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   455
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   456
    yield stream.makeframe(requestid=requestid,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   457
                           typeid=FRAME_TYPE_COMMAND_RESPONSE,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   458
                           flags=FLAG_COMMAND_RESPONSE_EOS,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   459
                           payload=overall)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
   460
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
   461
def createerrorframe(stream, requestid, msg, errtype):
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   462
    # 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
   463
    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
   464
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
   465
    payload = b''.join(cborutil.streamencode({
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
   466
        b'type': errtype,
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
   467
        b'message': [{b'msg': msg}],
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
   468
    }))
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   469
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   470
    yield stream.makeframe(requestid=requestid,
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   471
                           typeid=FRAME_TYPE_ERROR_RESPONSE,
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
   472
                           flags=0,
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
   473
                           payload=payload)
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   474
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
   475
def createtextoutputframe(stream, requestid, atoms,
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
   476
                          maxframesize=DEFAULT_MAX_FRAME_SIZE):
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   477
    """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
   478
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   479
    ``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
   480
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   481
    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
   482
    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
   483
    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
   484
    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
   485
    """
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
   486
    atomdicts = []
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   487
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   488
    for (formatting, args, labels) in atoms:
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   489
        # 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
   490
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   491
        if not isinstance(formatting, bytes):
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   492
            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
   493
        for arg in args:
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   494
            if not isinstance(arg, bytes):
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   495
                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
   496
        for label in labels:
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   497
            if not isinstance(label, bytes):
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   498
                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
   499
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
   500
        # Formatting string must be ASCII.
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
   501
        formatting = formatting.decode(r'ascii', r'replace').encode(r'ascii')
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   502
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   503
        # Arguments must be UTF-8.
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   504
        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
   505
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   506
        # Labels must be ASCII.
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   507
        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
   508
                  for l in labels]
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   509
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
   510
        atom = {b'msg': formatting}
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
   511
        if args:
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
   512
            atom[b'args'] = args
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
   513
        if labels:
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
   514
            atom[b'labels'] = labels
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   515
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
   516
        atomdicts.append(atom)
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   517
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
   518
    payload = b''.join(cborutil.streamencode(atomdicts))
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   519
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
   520
    if len(payload) > maxframesize:
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   521
        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
   522
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   523
    yield stream.makeframe(requestid=requestid,
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   524
                           typeid=FRAME_TYPE_TEXT_OUTPUT,
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   525
                           flags=0,
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
   526
                           payload=payload)
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   527
39576
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   528
class bufferingcommandresponseemitter(object):
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   529
    """Helper object to emit command response frames intelligently.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   530
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   531
    Raw command response data is likely emitted in chunks much smaller
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   532
    than what can fit in a single frame. This class exists to buffer
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   533
    chunks until enough data is available to fit in a single frame.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   534
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   535
    TODO we'll need something like this when compression is supported.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   536
    So it might make sense to implement this functionality at the stream
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   537
    level.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   538
    """
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   539
    def __init__(self, stream, requestid, maxframesize=DEFAULT_MAX_FRAME_SIZE):
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   540
        self._stream = stream
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   541
        self._requestid = requestid
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   542
        self._maxsize = maxframesize
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   543
        self._chunks = []
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   544
        self._chunkssize = 0
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   545
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   546
    def send(self, data):
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   547
        """Send new data for emission.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   548
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   549
        Is a generator of new frames that were derived from the new input.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   550
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   551
        If the special input ``None`` is received, flushes all buffered
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   552
        data to frames.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   553
        """
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   554
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   555
        if data is None:
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   556
            for frame in self._flush():
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   557
                yield frame
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   558
            return
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   559
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   560
        data = self._stream.encode(data)
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   561
39576
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   562
        # There is a ton of potential to do more complicated things here.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   563
        # Our immediate goal is to coalesce small chunks into big frames,
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   564
        # not achieve the fewest number of frames possible. So we go with
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   565
        # a simple implementation:
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   566
        #
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   567
        # * If a chunk is too large for a frame, we flush and emit frames
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   568
        #   for the new chunk.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   569
        # * If a chunk can be buffered without total buffered size limits
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   570
        #   being exceeded, we do that.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   571
        # * If a chunk causes us to go over our buffering limit, we flush
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   572
        #   and then buffer the new chunk.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   573
40136
3a6d6c54bd81 wireprotov2: don't emit empty frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40135
diff changeset
   574
        if not data:
3a6d6c54bd81 wireprotov2: don't emit empty frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40135
diff changeset
   575
            return
3a6d6c54bd81 wireprotov2: don't emit empty frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40135
diff changeset
   576
39576
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   577
        if len(data) > self._maxsize:
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   578
            for frame in self._flush():
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   579
                yield frame
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   580
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   581
            # Now emit frames for the big chunk.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   582
            offset = 0
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   583
            while True:
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   584
                chunk = data[offset:offset + self._maxsize]
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   585
                offset += len(chunk)
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   586
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   587
                yield self._stream.makeframe(
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   588
                    self._requestid,
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   589
                    typeid=FRAME_TYPE_COMMAND_RESPONSE,
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   590
                    flags=FLAG_COMMAND_RESPONSE_CONTINUATION,
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   591
                    payload=chunk,
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   592
                    encoded=True)
39576
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   593
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   594
                if offset == len(data):
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   595
                    return
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   596
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   597
        # If we don't have enough to constitute a full frame, buffer and
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   598
        # return.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   599
        if len(data) + self._chunkssize < self._maxsize:
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   600
            self._chunks.append(data)
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   601
            self._chunkssize += len(data)
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   602
            return
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   603
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   604
        # Else flush what we have and buffer the new chunk. We could do
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   605
        # something more intelligent here, like break the chunk. Let's
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   606
        # keep things simple for now.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   607
        for frame in self._flush():
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   608
            yield frame
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   609
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   610
        self._chunks.append(data)
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   611
        self._chunkssize = len(data)
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   612
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   613
    def _flush(self):
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   614
        payload = b''.join(self._chunks)
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   615
        assert len(payload) <= self._maxsize
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   616
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   617
        self._chunks[:] = []
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   618
        self._chunkssize = 0
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   619
40136
3a6d6c54bd81 wireprotov2: don't emit empty frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40135
diff changeset
   620
        if not payload:
3a6d6c54bd81 wireprotov2: don't emit empty frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40135
diff changeset
   621
            return
3a6d6c54bd81 wireprotov2: don't emit empty frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40135
diff changeset
   622
39576
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   623
        yield self._stream.makeframe(
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   624
            self._requestid,
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   625
            typeid=FRAME_TYPE_COMMAND_RESPONSE,
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   626
            flags=FLAG_COMMAND_RESPONSE_CONTINUATION,
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   627
            payload=payload,
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   628
            encoded=True)
39576
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
   629
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   630
# TODO consider defining encoders/decoders using the util.compressionengine
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   631
# mechanism.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   632
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   633
class identityencoder(object):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   634
    """Encoder for the "identity" stream encoding profile."""
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   635
    def __init__(self, ui):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   636
        pass
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   637
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   638
    def encode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   639
        return data
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   640
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   641
    def flush(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   642
        return b''
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   643
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   644
    def finish(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   645
        return b''
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   646
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   647
class identitydecoder(object):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   648
    """Decoder for the "identity" stream encoding profile."""
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   649
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   650
    def __init__(self, ui, extraobjs):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   651
        if extraobjs:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   652
            raise error.Abort(_('identity decoder received unexpected '
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   653
                                'additional values'))
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   654
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   655
    def decode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   656
        return data
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   657
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   658
class zlibencoder(object):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   659
    def __init__(self, ui):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   660
        import zlib
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   661
        self._zlib = zlib
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   662
        self._compressor = zlib.compressobj()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   663
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   664
    def encode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   665
        return self._compressor.compress(data)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   666
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   667
    def flush(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   668
        # Z_SYNC_FLUSH doesn't reset compression context, which is
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   669
        # what we want.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   670
        return self._compressor.flush(self._zlib.Z_SYNC_FLUSH)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   671
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   672
    def finish(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   673
        res = self._compressor.flush(self._zlib.Z_FINISH)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   674
        self._compressor = None
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   675
        return res
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   676
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   677
class zlibdecoder(object):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   678
    def __init__(self, ui, extraobjs):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   679
        import zlib
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   680
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   681
        if extraobjs:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   682
            raise error.Abort(_('zlib decoder received unexpected '
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   683
                                'additional values'))
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   684
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   685
        self._decompressor = zlib.decompressobj()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   686
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   687
    def decode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   688
        # Python 2's zlib module doesn't use the buffer protocol and can't
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   689
        # handle all bytes-like types.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   690
        if not pycompat.ispy3 and isinstance(data, bytearray):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   691
            data = bytes(data)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   692
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   693
        return self._decompressor.decompress(data)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   694
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   695
class zstdbaseencoder(object):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   696
    def __init__(self, level):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   697
        from . import zstd
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   698
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   699
        self._zstd = zstd
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   700
        cctx = zstd.ZstdCompressor(level=level)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   701
        self._compressor = cctx.compressobj()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   702
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   703
    def encode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   704
        return self._compressor.compress(data)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   705
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   706
    def flush(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   707
        # COMPRESSOBJ_FLUSH_BLOCK flushes all data previously fed into the
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   708
        # compressor and allows a decompressor to access all encoded data
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   709
        # up to this point.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   710
        return self._compressor.flush(self._zstd.COMPRESSOBJ_FLUSH_BLOCK)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   711
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   712
    def finish(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   713
        res = self._compressor.flush(self._zstd.COMPRESSOBJ_FLUSH_FINISH)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   714
        self._compressor = None
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   715
        return res
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   716
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   717
class zstd8mbencoder(zstdbaseencoder):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   718
    def __init__(self, ui):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   719
        super(zstd8mbencoder, self).__init__(3)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   720
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   721
class zstdbasedecoder(object):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   722
    def __init__(self, maxwindowsize):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   723
        from . import zstd
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   724
        dctx = zstd.ZstdDecompressor(max_window_size=maxwindowsize)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   725
        self._decompressor = dctx.decompressobj()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   726
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   727
    def decode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   728
        return self._decompressor.decompress(data)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   729
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   730
class zstd8mbdecoder(zstdbasedecoder):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   731
    def __init__(self, ui, extraobjs):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   732
        if extraobjs:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   733
            raise error.Abort(_('zstd8mb decoder received unexpected '
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   734
                                'additional values'))
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   735
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   736
        super(zstd8mbdecoder, self).__init__(maxwindowsize=8 * 1048576)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   737
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   738
# We lazily populate this to avoid excessive module imports when importing
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   739
# this module.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   740
STREAM_ENCODERS = {}
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   741
STREAM_ENCODERS_ORDER = []
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   742
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   743
def populatestreamencoders():
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   744
    if STREAM_ENCODERS:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   745
        return
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   746
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   747
    try:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   748
        from . import zstd
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   749
        zstd.__version__
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   750
    except ImportError:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   751
        zstd = None
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   752
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   753
    # zstandard is fastest and is preferred.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   754
    if zstd:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   755
        STREAM_ENCODERS[b'zstd-8mb'] = (zstd8mbencoder, zstd8mbdecoder)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   756
        STREAM_ENCODERS_ORDER.append(b'zstd-8mb')
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   757
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   758
    STREAM_ENCODERS[b'zlib'] = (zlibencoder, zlibdecoder)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   759
    STREAM_ENCODERS_ORDER.append(b'zlib')
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   760
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   761
    STREAM_ENCODERS[b'identity'] = (identityencoder, identitydecoder)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   762
    STREAM_ENCODERS_ORDER.append(b'identity')
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   763
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   764
class stream(object):
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   765
    """Represents a logical unidirectional series of frames."""
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   766
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   767
    def __init__(self, streamid, active=False):
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   768
        self.streamid = streamid
37655
b9502b5f2066 wireprotoframing: use value passed into function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37544
diff changeset
   769
        self._active = active
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   770
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   771
    def makeframe(self, requestid, typeid, flags, payload):
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   772
        """Create a frame to be sent out over this stream.
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   773
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   774
        Only returns the frame instance. Does not actually send it.
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
   775
        """
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   776
        streamflags = 0
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   777
        if not self._active:
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   778
            streamflags |= STREAM_FLAG_BEGIN_STREAM
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   779
            self._active = True
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   780
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   781
        return makeframe(requestid, self.streamid, streamflags, typeid, flags,
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   782
                         payload)
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   783
40131
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
   784
class inputstream(stream):
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
   785
    """Represents a stream used for receiving data."""
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
   786
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   787
    def __init__(self, streamid, active=False):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   788
        super(inputstream, self).__init__(streamid, active=active)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   789
        self._decoder = None
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   790
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   791
    def setdecoder(self, ui, name, extraobjs):
40129
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
   792
        """Set the decoder for this stream.
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
   793
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
   794
        Receives the stream profile name and any additional CBOR objects
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
   795
        decoded from the stream encoding settings frame payloads.
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
   796
        """
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   797
        if name not in STREAM_ENCODERS:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   798
            raise error.Abort(_('unknown stream decoder: %s') % name)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   799
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   800
        self._decoder = STREAM_ENCODERS[name][1](ui, extraobjs)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   801
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   802
    def decode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   803
        # Default is identity decoder. We don't bother instantiating one
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   804
        # because it is trivial.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   805
        if not self._decoder:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   806
            return data
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   807
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   808
        return self._decoder.decode(data)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   809
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   810
    def flush(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   811
        if not self._decoder:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   812
            return b''
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   813
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   814
        return self._decoder.flush()
40129
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
   815
40131
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
   816
class outputstream(stream):
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
   817
    """Represents a stream used for sending data."""
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
   818
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   819
    def __init__(self, streamid, active=False):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   820
        super(outputstream, self).__init__(streamid, active=active)
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   821
        self.streamsettingssent = False
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   822
        self._encoder = None
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   823
        self._encodername = None
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   824
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   825
    def setencoder(self, ui, name):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   826
        """Set the encoder for this stream.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   827
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   828
        Receives the stream profile name.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   829
        """
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   830
        if name not in STREAM_ENCODERS:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   831
            raise error.Abort(_('unknown stream encoder: %s') % name)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   832
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   833
        self._encoder = STREAM_ENCODERS[name][0](ui)
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   834
        self._encodername = name
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   835
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   836
    def encode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   837
        if not self._encoder:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   838
            return data
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   839
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   840
        return self._encoder.encode(data)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   841
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   842
    def flush(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   843
        if not self._encoder:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   844
            return b''
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   845
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   846
        return self._encoder.flush()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   847
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   848
    def finish(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   849
        if not self._encoder:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   850
            return b''
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   851
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   852
        self._encoder.finish()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   853
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   854
    def makeframe(self, requestid, typeid, flags, payload,
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   855
                  encoded=False):
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   856
        """Create a frame to be sent out over this stream.
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   857
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   858
        Only returns the frame instance. Does not actually send it.
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   859
        """
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   860
        streamflags = 0
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   861
        if not self._active:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   862
            streamflags |= STREAM_FLAG_BEGIN_STREAM
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   863
            self._active = True
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   864
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   865
        if encoded:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   866
            if not self.streamsettingssent:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   867
                raise error.ProgrammingError(
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   868
                    b'attempting to send encoded frame without sending stream '
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   869
                    b'settings')
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   870
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   871
            streamflags |= STREAM_FLAG_ENCODING_APPLIED
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   872
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   873
        if (typeid == FRAME_TYPE_STREAM_SETTINGS
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   874
            and flags & FLAG_STREAM_ENCODING_SETTINGS_EOS):
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   875
            self.streamsettingssent = True
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   876
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   877
        return makeframe(requestid, self.streamid, streamflags, typeid, flags,
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   878
                         payload)
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   879
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   880
    def makestreamsettingsframe(self, requestid):
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   881
        """Create a stream settings frame for this stream.
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   882
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   883
        Returns frame data or None if no stream settings frame is needed or has
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   884
        already been sent.
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   885
        """
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   886
        if not self._encoder or self.streamsettingssent:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   887
            return None
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   888
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   889
        payload = b''.join(cborutil.streamencode(self._encodername))
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   890
        return self.makeframe(requestid, FRAME_TYPE_STREAM_SETTINGS,
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   891
                              FLAG_STREAM_ENCODING_SETTINGS_EOS, payload)
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
   892
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   893
def ensureserverstream(stream):
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   894
    if stream.streamid % 2:
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   895
        raise error.ProgrammingError('server should only write to even '
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   896
                                     'numbered streams; %d is not even' %
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   897
                                     stream.streamid)
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
   898
40127
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
   899
DEFAULT_PROTOCOL_SETTINGS = {
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
   900
    'contentencodings': [b'identity'],
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
   901
}
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
   902
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   903
class serverreactor(object):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   904
    """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
   905
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   906
    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
   907
    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
   908
    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
   909
    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
   910
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   911
    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
   912
    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
   913
    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
   914
    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
   915
    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
   916
    *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
   917
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   918
    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
   919
    this class.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   920
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   921
    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
   922
    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
   923
    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
   924
    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
   925
    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
   926
    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
   927
    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
   928
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   929
    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
   930
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   931
    sendframes
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
   932
       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
   933
       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
   934
       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
   935
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   936
    error
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   937
       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
   938
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   939
    runcommand
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   940
       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
   941
       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
   942
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   943
    wantframe
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   944
       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
   945
       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
   946
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   947
    noop
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   948
       Indicates no additional action is required.
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   949
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   950
    Known Issues
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   951
    ------------
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   952
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   953
    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
   954
    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
   955
    server's memory.
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   956
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   957
    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
   958
    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
   959
    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
   960
    to facilitate graceful shutdown?
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   961
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   962
    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
   963
    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
   964
    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
   965
    between who responds to what.
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   966
    """
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   967
40130
293835e0fff7 wireprotov2: pass ui into clientreactor and serverreactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40129
diff changeset
   968
    def __init__(self, ui, deferoutput=False):
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   969
        """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
   970
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   971
        ``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
   972
        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
   973
        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
   974
        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
   975
        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
   976
        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
   977
        """
40130
293835e0fff7 wireprotov2: pass ui into clientreactor and serverreactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40129
diff changeset
   978
        self._ui = ui
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   979
        self._deferoutput = deferoutput
40127
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
   980
        self._state = 'initial'
37289
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
   981
        self._nextoutgoingstreamid = 2
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
   982
        self._bufferedframegens = []
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   983
        # stream id -> stream instance for all active streams from the client.
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
   984
        self._incomingstreams = {}
37289
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
   985
        self._outgoingstreams = {}
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
   986
        # 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
   987
        self._receivingcommands = {}
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   988
        # 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
   989
        # 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
   990
        # set.
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
   991
        self._activecommands = set()
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
   992
40127
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
   993
        self._protocolsettingsdecoder = None
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
   994
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
   995
        # Sender protocol settings are optional. Set implied default values.
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
   996
        self._sendersettings = dict(DEFAULT_PROTOCOL_SETTINGS)
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
   997
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   998
        populatestreamencoders()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
   999
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1000
    def onframerecv(self, frame):
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1001
        """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
  1002
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1003
        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
  1004
        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
  1005
        """
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1006
        if not frame.streamid % 2:
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1007
            self._state = 'errored'
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1008
            return self._makeerrorresult(
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1009
                _('received frame with even numbered stream ID: %d') %
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1010
                  frame.streamid)
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1011
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1012
        if frame.streamid not in self._incomingstreams:
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1013
            if not frame.streamflags & STREAM_FLAG_BEGIN_STREAM:
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1014
                self._state = 'errored'
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1015
                return self._makeerrorresult(
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1016
                    _('received frame on unknown inactive stream without '
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1017
                      'beginning of stream flag set'))
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1018
40131
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
  1019
            self._incomingstreams[frame.streamid] = inputstream(frame.streamid)
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1020
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1021
        if frame.streamflags & STREAM_FLAG_ENCODING_APPLIED:
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1022
            # TODO handle decoding frames
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1023
            self._state = 'errored'
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1024
            raise error.ProgrammingError('support for decoding stream payloads '
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1025
                                         'not yet implemented')
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1026
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1027
        if frame.streamflags & STREAM_FLAG_END_STREAM:
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1028
            del self._incomingstreams[frame.streamid]
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1029
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1030
        handlers = {
40127
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1031
            'initial': self._onframeinitial,
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1032
            'protocol-settings-receiving': self._onframeprotocolsettings,
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1033
            'idle': self._onframeidle,
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1034
            'command-receiving': self._onframecommandreceiving,
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1035
            'errored': self._onframeerrored,
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1036
        }
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1037
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1038
        meth = handlers.get(self._state)
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1039
        if not meth:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1040
            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
  1041
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1042
        return meth(frame)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1043
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1044
    def oncommandresponsereadyobjects(self, stream, requestid, objs):
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1045
        """Signal that objects are ready to be sent to the client.
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1046
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1047
        ``objs`` is an iterable of objects (typically a generator) that will
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1048
        be encoded via CBOR and added to frames, which will be sent to the
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1049
        client.
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1050
        """
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1051
        ensureserverstream(stream)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1052
40135
966b5f7fd30b wireprotov2: remove functions for creating response frames from bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40133
diff changeset
  1053
        # A more robust solution would be to check for objs.{next,__next__}.
966b5f7fd30b wireprotov2: remove functions for creating response frames from bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40133
diff changeset
  1054
        if isinstance(objs, list):
966b5f7fd30b wireprotov2: remove functions for creating response frames from bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40133
diff changeset
  1055
            objs = iter(objs)
966b5f7fd30b wireprotov2: remove functions for creating response frames from bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40133
diff changeset
  1056
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1057
        # We need to take care over exception handling. Uncaught exceptions
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1058
        # when generating frames could lead to premature end of the frame
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1059
        # stream and the possibility of the server or client process getting
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1060
        # in a bad state.
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1061
        #
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1062
        # Keep in mind that if ``objs`` is a generator, advancing it could
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1063
        # raise exceptions that originated in e.g. wire protocol command
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1064
        # functions. That is why we differentiate between exceptions raised
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1065
        # when iterating versus other exceptions that occur.
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1066
        #
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1067
        # In all cases, when the function finishes, the request is fully
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1068
        # handled and no new frames for it should be seen.
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1069
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1070
        def sendframes():
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1071
            emitted = False
40026
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1072
            alternatelocationsent = False
39576
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
  1073
            emitter = bufferingcommandresponseemitter(stream, requestid)
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1074
            while True:
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1075
                try:
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1076
                    o = next(objs)
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1077
                except StopIteration:
39576
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
  1078
                    for frame in emitter.send(None):
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
  1079
                        yield frame
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
  1080
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1081
                    if emitted:
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1082
                        for frame in createcommandresponseeosframes(
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1083
                            stream, requestid):
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1084
                            yield frame
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1085
                    break
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1086
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1087
                except error.WireprotoCommandError as e:
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1088
                    for frame in createcommanderrorresponse(
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1089
                        stream, requestid, e.message, e.messageargs):
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1090
                        yield frame
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1091
                    break
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1092
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1093
                except Exception as e:
39843
bce1c1af7518 py3: cast exception to bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39576
diff changeset
  1094
                    for frame in createerrorframe(
bce1c1af7518 py3: cast exception to bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39576
diff changeset
  1095
                        stream, requestid, '%s' % stringutil.forcebytestr(e),
bce1c1af7518 py3: cast exception to bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39576
diff changeset
  1096
                        errtype='server'):
bce1c1af7518 py3: cast exception to bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39576
diff changeset
  1097
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1098
                        yield frame
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1099
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1100
                    break
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1101
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1102
                try:
40026
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1103
                    # Alternate location responses can only be the first and
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1104
                    # only object in the output stream.
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1105
                    if isinstance(o, wireprototypes.alternatelocationresponse):
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1106
                        if emitted:
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1107
                            raise error.ProgrammingError(
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1108
                                'alternatelocationresponse seen after initial '
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1109
                                'output object')
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1110
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1111
                        frame = stream.makestreamsettingsframe(requestid)
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1112
                        if frame:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1113
                            yield frame
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1114
40026
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1115
                        yield createalternatelocationresponseframe(
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1116
                            stream, requestid, o)
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1117
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1118
                        alternatelocationsent = True
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1119
                        emitted = True
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1120
                        continue
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1121
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1122
                    if alternatelocationsent:
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1123
                        raise error.ProgrammingError(
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1124
                            'object follows alternatelocationresponse')
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1125
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1126
                    if not emitted:
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1127
                        # Frame is optional.
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1128
                        frame = stream.makestreamsettingsframe(requestid)
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1129
                        if frame:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1130
                            yield frame
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1131
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1132
                        # May be None if empty frame (due to encoding).
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1133
                        frame = createcommandresponseokframe(stream, requestid)
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1134
                        if frame:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1135
                            yield frame
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1136
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1137
                        emitted = True
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1138
40021
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1139
                    # Objects emitted by command functions can be serializable
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1140
                    # data structures or special types.
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1141
                    # TODO consider extracting the content normalization to a
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1142
                    # standalone function, as it may be useful for e.g. cachers.
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1143
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1144
                    # A pre-encoded object is sent directly to the emitter.
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1145
                    if isinstance(o, wireprototypes.encodedresponse):
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1146
                        for frame in emitter.send(o.data):
39576
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
  1147
                            yield frame
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
  1148
40328
2c55716f8a1c wireprotov2: add response type that serializes to indefinite length bytestring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40138
diff changeset
  1149
                    elif isinstance(
2c55716f8a1c wireprotov2: add response type that serializes to indefinite length bytestring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40138
diff changeset
  1150
                        o, wireprototypes.indefinitebytestringresponse):
2c55716f8a1c wireprotov2: add response type that serializes to indefinite length bytestring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40138
diff changeset
  1151
                        for chunk in cborutil.streamencodebytestringfromiter(
2c55716f8a1c wireprotov2: add response type that serializes to indefinite length bytestring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40138
diff changeset
  1152
                            o.chunks):
2c55716f8a1c wireprotov2: add response type that serializes to indefinite length bytestring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40138
diff changeset
  1153
2c55716f8a1c wireprotov2: add response type that serializes to indefinite length bytestring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40138
diff changeset
  1154
                            for frame in emitter.send(chunk):
2c55716f8a1c wireprotov2: add response type that serializes to indefinite length bytestring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40138
diff changeset
  1155
                                yield frame
2c55716f8a1c wireprotov2: add response type that serializes to indefinite length bytestring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40138
diff changeset
  1156
40021
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1157
                    # A regular object is CBOR encoded.
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1158
                    else:
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1159
                        for chunk in cborutil.streamencode(o):
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1160
                            for frame in emitter.send(chunk):
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1161
                                yield frame
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
  1162
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1163
                except Exception as e:
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1164
                    for frame in createerrorframe(stream, requestid,
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1165
                                                  '%s' % e,
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1166
                                                  errtype='server'):
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1167
                        yield frame
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1168
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
  1169
                    break
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1170
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1171
            self._activecommands.remove(requestid)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1172
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1173
        return self._handlesendframes(sendframes())
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1174
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
  1175
    def oninputeof(self):
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
  1176
        """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
  1177
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
  1178
        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
  1179
        completed.
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
  1180
        """
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1181
        # 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
  1182
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
  1183
        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
  1184
            return 'noop', {}
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
  1185
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
  1186
        # 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
  1187
        def makegen():
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
  1188
            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
  1189
                for frame in gen:
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
  1190
                    yield frame
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
  1191
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
  1192
        return 'sendframes', {
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
  1193
            'framegen': makegen(),
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
  1194
        }
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
  1195
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1196
    def _handlesendframes(self, framegen):
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1197
        if self._deferoutput:
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1198
            self._bufferedframegens.append(framegen)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1199
            return 'noop', {}
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1200
        else:
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1201
            return 'sendframes', {
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1202
                'framegen': framegen,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1203
            }
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1204
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1205
    def onservererror(self, stream, requestid, msg):
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1206
        ensureserverstream(stream)
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
  1207
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1208
        def sendframes():
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1209
            for frame in createerrorframe(stream, requestid, msg,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1210
                                          errtype='server'):
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1211
                yield frame
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1212
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1213
            self._activecommands.remove(requestid)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1214
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1215
        return self._handlesendframes(sendframes())
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1216
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1217
    def oncommanderror(self, stream, requestid, message, args=None):
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1218
        """Called when a command encountered an error before sending output."""
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1219
        ensureserverstream(stream)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1220
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1221
        def sendframes():
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1222
            for frame in createcommanderrorresponse(stream, requestid, message,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1223
                                                    args):
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1224
                yield frame
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1225
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1226
            self._activecommands.remove(requestid)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1227
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
  1228
        return self._handlesendframes(sendframes())
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
  1229
37289
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
  1230
    def makeoutputstream(self):
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1231
        """Create a stream to be used for sending data to the client.
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1232
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1233
        If this is called before protocol settings frames are received, we
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1234
        don't know what stream encodings are supported by the client and
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1235
        we will default to identity.
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1236
        """
37289
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
  1237
        streamid = self._nextoutgoingstreamid
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
  1238
        self._nextoutgoingstreamid += 2
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
  1239
40131
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
  1240
        s = outputstream(streamid)
37289
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
  1241
        self._outgoingstreams[streamid] = s
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
  1242
40138
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1243
        # Always use the *server's* preferred encoder over the client's,
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1244
        # as servers have more to lose from sub-optimal encoders being used.
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1245
        for name in STREAM_ENCODERS_ORDER:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1246
            if name in self._sendersettings['contentencodings']:
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1247
                s.setencoder(self._ui, name)
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1248
                break
b5bf3dd6ec5b wireprotov2: send content encoded frames from server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40136
diff changeset
  1249
37289
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
  1250
        return s
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
  1251
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1252
    def _makeerrorresult(self, msg):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1253
        return 'error', {
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1254
            'message': msg,
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1255
        }
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1256
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1257
    def _makeruncommandresult(self, requestid):
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1258
        entry = self._receivingcommands[requestid]
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1259
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1260
        if not entry['requestdone']:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1261
            self._state = 'errored'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1262
            raise error.ProgrammingError('should not be called without '
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1263
                                         'requestdone set')
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1264
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1265
        del self._receivingcommands[requestid]
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1266
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1267
        if self._receivingcommands:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1268
            self._state = 'command-receiving'
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1269
        else:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1270
            self._state = 'idle'
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1271
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1272
        # Decode the payloads as CBOR.
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1273
        entry['payload'].seek(0)
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
  1274
        request = cborutil.decodeall(entry['payload'].getvalue())[0]
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1275
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1276
        if b'name' not in request:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1277
            self._state = 'errored'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1278
            return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1279
                _('command request missing "name" field'))
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1280
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1281
        if b'args' not in request:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1282
            request[b'args'] = {}
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1283
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
  1284
        assert requestid not in self._activecommands
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
  1285
        self._activecommands.add(requestid)
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
  1286
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1287
        return 'runcommand', {
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1288
            'requestid': requestid,
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1289
            'command': request[b'name'],
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1290
            'args': request[b'args'],
40026
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
  1291
            'redirect': request.get(b'redirect'),
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1292
            '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
  1293
        }
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1294
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1295
    def _makewantframeresult(self):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1296
        return 'wantframe', {
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1297
            'state': self._state,
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1298
        }
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1299
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1300
    def _validatecommandrequestframe(self, frame):
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1301
        new = frame.flags & FLAG_COMMAND_REQUEST_NEW
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1302
        continuation = frame.flags & FLAG_COMMAND_REQUEST_CONTINUATION
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1303
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1304
        if new and continuation:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1305
            self._state = 'errored'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1306
            return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1307
                _('received command request frame with both new and '
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1308
                  'continuation flags set'))
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1309
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1310
        if not new and not continuation:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1311
            self._state = 'errored'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1312
            return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1313
                _('received command request frame with neither new nor '
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1314
                  'continuation flags set'))
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1315
40127
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1316
    def _onframeinitial(self, frame):
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1317
        # Called when we receive a frame when in the "initial" state.
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1318
        if frame.typeid == FRAME_TYPE_SENDER_PROTOCOL_SETTINGS:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1319
            self._state = 'protocol-settings-receiving'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1320
            self._protocolsettingsdecoder = cborutil.bufferingdecoder()
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1321
            return self._onframeprotocolsettings(frame)
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1322
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1323
        elif frame.typeid == FRAME_TYPE_COMMAND_REQUEST:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1324
            self._state = 'idle'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1325
            return self._onframeidle(frame)
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1326
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1327
        else:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1328
            self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1329
            return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1330
                _('expected sender protocol settings or command request '
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1331
                  'frame; got %d') % frame.typeid)
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1332
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1333
    def _onframeprotocolsettings(self, frame):
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1334
        assert self._state == 'protocol-settings-receiving'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1335
        assert self._protocolsettingsdecoder is not None
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1336
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1337
        if frame.typeid != FRAME_TYPE_SENDER_PROTOCOL_SETTINGS:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1338
            self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1339
            return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1340
                _('expected sender protocol settings frame; got %d') %
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1341
                frame.typeid)
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1342
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1343
        more = frame.flags & FLAG_SENDER_PROTOCOL_SETTINGS_CONTINUATION
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1344
        eos = frame.flags & FLAG_SENDER_PROTOCOL_SETTINGS_EOS
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1345
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1346
        if more and eos:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1347
            self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1348
            return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1349
                _('sender protocol settings frame cannot have both '
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1350
                  'continuation and end of stream flags set'))
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1351
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1352
        if not more and not eos:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1353
            self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1354
            return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1355
                _('sender protocol settings frame must have continuation or '
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1356
                  'end of stream flag set'))
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1357
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1358
        # TODO establish limits for maximum amount of data that can be
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1359
        # buffered.
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1360
        try:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1361
            self._protocolsettingsdecoder.decode(frame.payload)
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1362
        except Exception as e:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1363
            self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1364
            return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1365
                _('error decoding CBOR from sender protocol settings frame: %s')
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1366
                % stringutil.forcebytestr(e))
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1367
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1368
        if more:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1369
            return self._makewantframeresult()
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1370
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1371
        assert eos
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1372
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1373
        decoded = self._protocolsettingsdecoder.getavailable()
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1374
        self._protocolsettingsdecoder = None
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1375
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1376
        if not decoded:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1377
            self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1378
            return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1379
                _('sender protocol settings frame did not contain CBOR data'))
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1380
        elif len(decoded) > 1:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1381
            self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1382
            return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1383
                _('sender protocol settings frame contained multiple CBOR '
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1384
                  'values'))
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1385
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1386
        d = decoded[0]
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1387
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1388
        if b'contentencodings' in d:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1389
            self._sendersettings['contentencodings'] = d[b'contentencodings']
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1390
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1391
        self._state = 'idle'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1392
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1393
        return self._makewantframeresult()
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
  1394
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1395
    def _onframeidle(self, frame):
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1396
        # 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
  1397
        # command request.
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1398
        if frame.typeid != FRAME_TYPE_COMMAND_REQUEST:
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1399
            self._state = 'errored'
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1400
            return self._makeerrorresult(
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1401
                _('expected command request frame; got %d') % frame.typeid)
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1402
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1403
        res = self._validatecommandrequestframe(frame)
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1404
        if res:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1405
            return res
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1406
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1407
        if frame.requestid in self._receivingcommands:
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1408
            self._state = 'errored'
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1409
            return self._makeerrorresult(
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1410
                _('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
  1411
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
  1412
        if frame.requestid in self._activecommands:
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
  1413
            self._state = 'errored'
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1414
            return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1415
                _('request with ID %d is already active') % frame.requestid)
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1416
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1417
        new = frame.flags & FLAG_COMMAND_REQUEST_NEW
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1418
        moreframes = frame.flags & FLAG_COMMAND_REQUEST_MORE_FRAMES
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1419
        expectingdata = frame.flags & FLAG_COMMAND_REQUEST_EXPECT_DATA
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
  1420
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1421
        if not new:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1422
            self._state = 'errored'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1423
            return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1424
                _('received command request frame without new flag set'))
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1425
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1426
        payload = util.bytesio()
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1427
        payload.write(frame.payload)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1428
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1429
        self._receivingcommands[frame.requestid] = {
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1430
            'payload': payload,
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1431
            'data': None,
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1432
            'requestdone': not moreframes,
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1433
            'expectingdata': bool(expectingdata),
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1434
        }
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1435
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1436
        # This is the final frame for this request. Dispatch it.
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1437
        if not moreframes and not expectingdata:
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1438
            return self._makeruncommandresult(frame.requestid)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1439
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1440
        assert moreframes or expectingdata
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1441
        self._state = 'command-receiving'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1442
        return self._makewantframeresult()
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1443
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1444
    def _onframecommandreceiving(self, frame):
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1445
        if frame.typeid == FRAME_TYPE_COMMAND_REQUEST:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1446
            # Process new command requests as such.
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1447
            if frame.flags & FLAG_COMMAND_REQUEST_NEW:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1448
                return self._onframeidle(frame)
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1449
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1450
            res = self._validatecommandrequestframe(frame)
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1451
            if res:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1452
                return res
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1453
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1454
        # 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
  1455
        # receiving but is not active.
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
  1456
        if frame.requestid in self._activecommands:
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
  1457
            self._state = 'errored'
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
  1458
            return self._makeerrorresult(
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
  1459
                _('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
  1460
                frame.requestid)
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
  1461
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1462
        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
  1463
            self._state = 'errored'
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1464
            return self._makeerrorresult(
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1465
                _('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
  1466
                  frame.requestid)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1467
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1468
        entry = self._receivingcommands[frame.requestid]
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1469
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1470
        if frame.typeid == FRAME_TYPE_COMMAND_REQUEST:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1471
            moreframes = frame.flags & FLAG_COMMAND_REQUEST_MORE_FRAMES
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1472
            expectingdata = bool(frame.flags & FLAG_COMMAND_REQUEST_EXPECT_DATA)
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1473
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1474
            if entry['requestdone']:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1475
                self._state = 'errored'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1476
                return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1477
                    _('received command request frame when request frames '
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1478
                      'were supposedly done'))
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1479
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1480
            if expectingdata != entry['expectingdata']:
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1481
                self._state = 'errored'
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1482
                return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1483
                    _('mismatch between expect data flag and previous frame'))
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1484
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1485
            entry['payload'].write(frame.payload)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1486
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1487
            if not moreframes:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1488
                entry['requestdone'] = True
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1489
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1490
            if not moreframes and not expectingdata:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1491
                return self._makeruncommandresult(frame.requestid)
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1492
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1493
            return self._makewantframeresult()
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1494
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1495
        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
  1496
            if not entry['expectingdata']:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1497
                self._state = 'errored'
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1498
                return self._makeerrorresult(_(
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1499
                    '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
  1500
                    'expecting data: %d') % frame.requestid)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1501
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1502
            if entry['data'] is None:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1503
                entry['data'] = util.bytesio()
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
  1504
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1505
            return self._handlecommanddataframe(frame, entry)
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1506
        else:
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1507
            self._state = 'errored'
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1508
            return self._makeerrorresult(_(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
  1509
                'received unexpected frame type: %d') % frame.typeid)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1510
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1511
    def _handlecommanddataframe(self, frame, entry):
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1512
        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
  1513
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1514
        # 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
  1515
        entry['data'].write(frame.payload)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1516
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1517
        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
  1518
            return self._makewantframeresult()
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1519
        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
  1520
            entry['data'].seek(0)
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1521
            return self._makeruncommandresult(frame.requestid)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1522
        else:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1523
            self._state = 'errored'
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1524
            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
  1525
                                           'flags'))
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1526
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
  1527
    def _onframeerrored(self, frame):
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
  1528
        return self._makeerrorresult(_('server already errored'))
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1529
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1530
class commandrequest(object):
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1531
    """Represents a request to run a command."""
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1532
40025
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
  1533
    def __init__(self, requestid, name, args, datafh=None, redirect=None):
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1534
        self.requestid = requestid
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1535
        self.name = name
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1536
        self.args = args
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1537
        self.datafh = datafh
40025
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
  1538
        self.redirect = redirect
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1539
        self.state = 'pending'
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1540
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1541
class clientreactor(object):
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1542
    """Holds state of a client issuing frame-based protocol requests.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1544
    This is like ``serverreactor`` but for client-side state.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1545
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1546
    Each instance is bound to the lifetime of a connection. For persistent
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1547
    connection transports using e.g. TCP sockets and speaking the raw
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1548
    framing protocol, there will be a single instance for the lifetime of
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1549
    the TCP socket. For transports where there are multiple discrete
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1550
    interactions (say tunneled within in HTTP request), there will be a
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1551
    separate instance for each distinct interaction.
40128
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1552
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1553
    Consumers are expected to tell instances when events occur by calling
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1554
    various methods. These methods return a 2-tuple describing any follow-up
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1555
    action(s) to take. The first element is the name of an action to
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1556
    perform. The second is a data structure (usually a dict) specific to
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1557
    that action that contains more information. e.g. if the reactor wants
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1558
    to send frames to the server, the data structure will contain a reference
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1559
    to those frames.
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1560
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1561
    Valid actions that consumers can be instructed to take are:
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1562
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1563
    noop
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1564
       Indicates no additional action is required.
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1565
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1566
    sendframes
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1567
       Indicates that frames should be sent to the server. The ``framegen``
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1568
       key contains a generator of frames that should be sent. The reactor
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1569
       assumes that all frames in this generator are sent to the server.
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1570
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1571
    error
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1572
       Indicates that an error occurred. The ``message`` key contains an
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1573
       error message describing the failure.
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1574
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1575
    responsedata
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1576
       Indicates a response to a previously-issued command was received.
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1577
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1578
       The ``request`` key contains the ``commandrequest`` instance that
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1579
       represents the request this data is for.
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1580
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1581
       The ``data`` key contains the decoded data from the server.
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1582
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1583
       ``expectmore`` and ``eos`` evaluate to True when more response data
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1584
       is expected to follow or we're at the end of the response stream,
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
  1585
       respectively.
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1586
    """
40133
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1587
    def __init__(self, ui, hasmultiplesend=False, buffersends=True,
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1588
                 clientcontentencoders=None):
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1589
        """Create a new instance.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1590
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1591
        ``hasmultiplesend`` indicates whether multiple sends are supported
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1592
        by the transport. When True, it is possible to send commands immediately
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1593
        instead of buffering until the caller signals an intent to finish a
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1594
        send operation.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1595
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1596
        ``buffercommands`` indicates whether sends should be buffered until the
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1597
        last request has been issued.
40133
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1598
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1599
        ``clientcontentencoders`` is an iterable of content encoders the client
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1600
        will advertise to the server and that the server can use for encoding
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1601
        data. If not defined, the client will not advertise content encoders
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1602
        to the server.
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1603
        """
40130
293835e0fff7 wireprotov2: pass ui into clientreactor and serverreactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40129
diff changeset
  1604
        self._ui = ui
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1605
        self._hasmultiplesend = hasmultiplesend
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1606
        self._buffersends = buffersends
40133
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1607
        self._clientcontentencoders = clientcontentencoders
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1608
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1609
        self._canissuecommands = True
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1610
        self._cansend = True
40133
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1611
        self._protocolsettingssent = False
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1612
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1613
        self._nextrequestid = 1
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1614
        # We only support a single outgoing stream for now.
40131
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
  1615
        self._outgoingstream = outputstream(1)
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1616
        self._pendingrequests = collections.deque()
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1617
        self._activerequests = {}
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1618
        self._incomingstreams = {}
40129
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1619
        self._streamsettingsdecoders = {}
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1620
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
  1621
        populatestreamencoders()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
  1622
40025
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
  1623
    def callcommand(self, name, args, datafh=None, redirect=None):
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1624
        """Request that a command be executed.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1625
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1626
        Receives the command name, a dict of arguments to pass to the command,
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1627
        and an optional file object containing the raw data for the command.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1628
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1629
        Returns a 3-tuple of (request, action, action data).
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1630
        """
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1631
        if not self._canissuecommands:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1632
            raise error.ProgrammingError('cannot issue new commands')
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1633
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1634
        requestid = self._nextrequestid
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1635
        self._nextrequestid += 2
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1636
40025
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
  1637
        request = commandrequest(requestid, name, args, datafh=datafh,
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
  1638
                                 redirect=redirect)
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1639
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1640
        if self._buffersends:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1641
            self._pendingrequests.append(request)
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1642
            return request, 'noop', {}
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1643
        else:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1644
            if not self._cansend:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1645
                raise error.ProgrammingError('sends cannot be performed on '
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1646
                                             'this instance')
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1647
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1648
            if not self._hasmultiplesend:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1649
                self._cansend = False
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1650
                self._canissuecommands = False
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1651
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1652
            return request, 'sendframes', {
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1653
                'framegen': self._makecommandframes(request),
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1654
            }
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1655
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1656
    def flushcommands(self):
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1657
        """Request that all queued commands be sent.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1658
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1659
        If any commands are buffered, this will instruct the caller to send
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1660
        them over the wire. If no commands are buffered it instructs the client
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1661
        to no-op.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1662
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1663
        If instances aren't configured for multiple sends, no new command
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1664
        requests are allowed after this is called.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1665
        """
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1666
        if not self._pendingrequests:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1667
            return 'noop', {}
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1668
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1669
        if not self._cansend:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1670
            raise error.ProgrammingError('sends cannot be performed on this '
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1671
                                         'instance')
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1672
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1673
        # If the instance only allows sending once, mark that we have fired
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1674
        # our one shot.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1675
        if not self._hasmultiplesend:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1676
            self._canissuecommands = False
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1677
            self._cansend = False
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1678
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1679
        def makeframes():
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1680
            while self._pendingrequests:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1681
                request = self._pendingrequests.popleft()
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1682
                for frame in self._makecommandframes(request):
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1683
                    yield frame
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1684
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1685
        return 'sendframes', {
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1686
            'framegen': makeframes(),
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1687
        }
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1688
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1689
    def _makecommandframes(self, request):
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1690
        """Emit frames to issue a command request.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1691
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1692
        As a side-effect, update request accounting to reflect its changed
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1693
        state.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1694
        """
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1695
        self._activerequests[request.requestid] = request
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1696
        request.state = 'sending'
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1697
40133
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1698
        if not self._protocolsettingssent and self._clientcontentencoders:
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1699
            self._protocolsettingssent = True
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1700
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1701
            payload = b''.join(cborutil.streamencode({
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1702
                b'contentencodings': self._clientcontentencoders,
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1703
            }))
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1704
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1705
            yield self._outgoingstream.makeframe(
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1706
                requestid=request.requestid,
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1707
                typeid=FRAME_TYPE_SENDER_PROTOCOL_SETTINGS,
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1708
                flags=FLAG_SENDER_PROTOCOL_SETTINGS_EOS,
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1709
                payload=payload)
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
  1710
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1711
        res = createcommandframes(self._outgoingstream,
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1712
                                  request.requestid,
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1713
                                  request.name,
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1714
                                  request.args,
40025
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
  1715
                                  datafh=request.datafh,
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
  1716
                                  redirect=request.redirect)
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1717
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1718
        for frame in res:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1719
            yield frame
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1720
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
  1721
        request.state = 'sent'
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1722
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1723
    def onframerecv(self, frame):
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1724
        """Process a frame that has been received off the wire.
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1725
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1726
        Returns a 2-tuple of (action, meta) describing further action the
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1727
        caller needs to take as a result of receiving this frame.
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1728
        """
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1729
        if frame.streamid % 2:
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1730
            return 'error', {
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1731
                'message': (
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1732
                    _('received frame with odd numbered stream ID: %d') %
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1733
                    frame.streamid),
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1734
            }
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1735
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1736
        if frame.streamid not in self._incomingstreams:
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1737
            if not frame.streamflags & STREAM_FLAG_BEGIN_STREAM:
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1738
                return 'error', {
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1739
                    'message': _('received frame on unknown stream '
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1740
                                 'without beginning of stream flag set'),
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1741
                }
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1742
40131
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
  1743
            self._incomingstreams[frame.streamid] = inputstream(
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
  1744
                frame.streamid)
37656
e6870bca1f47 wireprotoframing: record when new stream is encountered
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37655
diff changeset
  1745
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
  1746
        stream = self._incomingstreams[frame.streamid]
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
  1747
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
  1748
        # If the payload is encoded, ask the stream to decode it. We
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
  1749
        # merely substitute the decoded result into the frame payload as
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
  1750
        # if it had been transferred all along.
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1751
        if frame.streamflags & STREAM_FLAG_ENCODING_APPLIED:
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
  1752
            frame.payload = stream.decode(frame.payload)
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1753
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1754
        if frame.streamflags & STREAM_FLAG_END_STREAM:
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1755
            del self._incomingstreams[frame.streamid]
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1756
40129
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1757
        if frame.typeid == FRAME_TYPE_STREAM_SETTINGS:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1758
            return self._onstreamsettingsframe(frame)
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1759
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1760
        if frame.requestid not in self._activerequests:
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1761
            return 'error', {
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1762
                'message': (_('received frame for inactive request ID: %d') %
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1763
                            frame.requestid),
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1764
            }
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1765
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1766
        request = self._activerequests[frame.requestid]
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1767
        request.state = 'receiving'
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1768
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1769
        handlers = {
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
  1770
            FRAME_TYPE_COMMAND_RESPONSE: self._oncommandresponseframe,
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1771
            FRAME_TYPE_ERROR_RESPONSE: self._onerrorresponseframe,
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1772
        }
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1773
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1774
        meth = handlers.get(frame.typeid)
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1775
        if not meth:
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1776
            raise error.ProgrammingError('unhandled frame type: %d' %
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1777
                                         frame.typeid)
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1778
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1779
        return meth(request, frame)
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1780
40129
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1781
    def _onstreamsettingsframe(self, frame):
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1782
        assert frame.typeid == FRAME_TYPE_STREAM_SETTINGS
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1783
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1784
        more = frame.flags & FLAG_STREAM_ENCODING_SETTINGS_CONTINUATION
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1785
        eos = frame.flags & FLAG_STREAM_ENCODING_SETTINGS_EOS
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1786
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1787
        if more and eos:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1788
            return 'error', {
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1789
                'message': (_('stream encoding settings frame cannot have both '
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1790
                              'continuation and end of stream flags set')),
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1791
            }
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1792
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1793
        if not more and not eos:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1794
            return 'error', {
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1795
                'message': _('stream encoding settings frame must have '
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1796
                             'continuation or end of stream flag set'),
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1797
            }
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1798
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1799
        if frame.streamid not in self._streamsettingsdecoders:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1800
            decoder = cborutil.bufferingdecoder()
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1801
            self._streamsettingsdecoders[frame.streamid] = decoder
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1802
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1803
        decoder = self._streamsettingsdecoders[frame.streamid]
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1804
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1805
        try:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1806
            decoder.decode(frame.payload)
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1807
        except Exception as e:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1808
            return 'error', {
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1809
                'message': (_('error decoding CBOR from stream encoding '
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1810
                             'settings frame: %s') %
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1811
                           stringutil.forcebytestr(e)),
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1812
            }
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1813
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1814
        if more:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1815
            return 'noop', {}
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1816
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1817
        assert eos
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1818
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1819
        decoded = decoder.getavailable()
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1820
        del self._streamsettingsdecoders[frame.streamid]
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1821
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1822
        if not decoded:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1823
            return 'error', {
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1824
                'message': _('stream encoding settings frame did not contain '
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1825
                             'CBOR data'),
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1826
            }
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1827
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1828
        try:
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
  1829
            self._incomingstreams[frame.streamid].setdecoder(self._ui,
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
  1830
                                                             decoded[0],
40129
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1831
                                                             decoded[1:])
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1832
        except Exception as e:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1833
            return 'error', {
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1834
                'message': (_('error setting stream decoder: %s') %
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1835
                            stringutil.forcebytestr(e)),
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1836
            }
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1837
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1838
        return 'noop', {}
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
  1839
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
  1840
    def _oncommandresponseframe(self, request, frame):
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
  1841
        if frame.flags & FLAG_COMMAND_RESPONSE_EOS:
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1842
            request.state = 'received'
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1843
            del self._activerequests[request.requestid]
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1844
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1845
        return 'responsedata', {
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1846
            'request': request,
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
  1847
            'expectmore': frame.flags & FLAG_COMMAND_RESPONSE_CONTINUATION,
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
  1848
            'eos': frame.flags & FLAG_COMMAND_RESPONSE_EOS,
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1849
            'data': frame.payload,
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
  1850
        }
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1851
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1852
    def _onerrorresponseframe(self, request, frame):
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1853
        request.state = 'errored'
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1854
        del self._activerequests[request.requestid]
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1855
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1856
        # The payload should be a CBOR map.
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
  1857
        m = cborutil.decodeall(frame.payload)[0]
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1858
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1859
        return 'error', {
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1860
            'request': request,
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1861
            'type': m['type'],
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1862
            'message': m['message'],
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
  1863
        }