annotate mercurial/wireprotoframing.py @ 40133:762ef19a07e3

wireprotov2: send protocol settings frame from client Now that we have client and server reactor support for protocol settings and encoding frames, we can start to send them out over the wire! This commit teaches the client reactor to send out a protocol settings frame when needed. The httpv2 peer has been taught to gather a list of supported content encoders and to advertise them through the client reactor. Because the client is now sending new frame types by default, this constitutes a compatibility break in the framing protocol. The media type version has been bumped accordingly. This will ensure existing clients won't attempt to send the new frames to old servers not supporting this explicit media type. I'm not bothering with the BC annotation because everything wireprotov2 is highly experimental and nobody should be running a server yet. Differential Revision: https://phab.mercurial-scm.org/D4922
author Gregory Szorc <gregory.szorc@gmail.com>
date Mon, 08 Oct 2018 17:00:16 -0700
parents e67522413ca8
children 966b5f7fd30b
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
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
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
368 def createcommandresponseframesfrombytes(stream, requestid, data,
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
369 maxframesize=DEFAULT_MAX_FRAME_SIZE):
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
370 """Create a raw frame to send a bytes response from static bytes input.
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
371
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
372 Returns a generator of bytearrays.
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
373 """
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37724
diff changeset
374 # Automatically send the overall CBOR response map.
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
375 overall = b''.join(cborutil.streamencode({b'status': b'ok'}))
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37724
diff changeset
376 if len(overall) > maxframesize:
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37724
diff changeset
377 raise error.ProgrammingError('not yet implemented')
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
378
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37724
diff changeset
379 # Simple case where we can fit the full response in a single frame.
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37724
diff changeset
380 if len(overall) + len(data) <= maxframesize:
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
381 flags = FLAG_COMMAND_RESPONSE_EOS
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
382 yield stream.makeframe(requestid=requestid,
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
383 typeid=FRAME_TYPE_COMMAND_RESPONSE,
37485
0b7475ea38cf wireproto: port heads command to wire protocol v2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37476
diff changeset
384 flags=flags,
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37724
diff changeset
385 payload=overall + data)
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
386 return
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
387
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37724
diff changeset
388 # It's easier to send the overall CBOR map in its own frame than to track
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37724
diff changeset
389 # offsets.
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37724
diff changeset
390 yield stream.makeframe(requestid=requestid,
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37724
diff changeset
391 typeid=FRAME_TYPE_COMMAND_RESPONSE,
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37724
diff changeset
392 flags=FLAG_COMMAND_RESPONSE_CONTINUATION,
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37724
diff changeset
393 payload=overall)
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37724
diff changeset
394
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
395 offset = 0
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
396 while True:
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
397 chunk = data[offset:offset + maxframesize]
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
398 offset += len(chunk)
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
399 done = offset == len(data)
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
400
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
401 if done:
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
402 flags = FLAG_COMMAND_RESPONSE_EOS
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
403 else:
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
404 flags = FLAG_COMMAND_RESPONSE_CONTINUATION
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
405
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
406 yield stream.makeframe(requestid=requestid,
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
407 typeid=FRAME_TYPE_COMMAND_RESPONSE,
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
408 flags=flags,
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
409 payload=chunk)
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
410
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
411 if done:
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
412 break
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
413
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
414 def createbytesresponseframesfromgen(stream, requestid, gen,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
415 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
416 """Generator of frames from a generator of byte chunks.
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
417
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
418 This assumes that another frame will follow whatever this emits. i.e.
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
419 this always emits the continuation flag and never emits the end-of-stream
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
420 flag.
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
421 """
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
422 cb = util.chunkbuffer(gen)
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
423 flags = FLAG_COMMAND_RESPONSE_CONTINUATION
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
424
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
425 while True:
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
426 chunk = cb.read(maxframesize)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
427 if not chunk:
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
428 break
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
429
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
430 yield stream.makeframe(requestid=requestid,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
431 typeid=FRAME_TYPE_COMMAND_RESPONSE,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
432 flags=flags,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
433 payload=chunk)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
434
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
435 flags |= FLAG_COMMAND_RESPONSE_CONTINUATION
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
436
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
437 def createcommandresponseokframe(stream, requestid):
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
438 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
439
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
440 return stream.makeframe(requestid=requestid,
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
441 typeid=FRAME_TYPE_COMMAND_RESPONSE,
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
442 flags=FLAG_COMMAND_RESPONSE_CONTINUATION,
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
443 payload=overall)
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
444
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
445 def createcommandresponseeosframe(stream, requestid):
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
446 """Create an empty payload frame representing command end-of-stream."""
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
447 return stream.makeframe(requestid=requestid,
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
448 typeid=FRAME_TYPE_COMMAND_RESPONSE,
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
449 flags=FLAG_COMMAND_RESPONSE_EOS,
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
450 payload=b'')
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
451
40026
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
452 def createalternatelocationresponseframe(stream, requestid, location):
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
453 data = {
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
454 b'status': b'redirect',
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
455 b'location': {
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
456 b'url': location.url,
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
457 b'mediatype': location.mediatype,
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
458 }
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
459 }
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
460
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
461 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
462 r'servercadercerts'):
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
463 value = getattr(location, a)
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
464 if value is not None:
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
465 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
466
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
467 return stream.makeframe(requestid=requestid,
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
468 typeid=FRAME_TYPE_COMMAND_RESPONSE,
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
469 flags=FLAG_COMMAND_RESPONSE_CONTINUATION,
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
470 payload=b''.join(cborutil.streamencode(data)))
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
471
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
472 def createcommanderrorresponse(stream, requestid, message, args=None):
39503
43d92d68ac88 wireprotov2peer: properly format errors
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39465
diff changeset
473 # 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
474 # formatting works consistently?
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
475 m = {
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
476 b'status': b'error',
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
477 b'error': {
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
478 b'message': message,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
479 }
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
480 }
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
481
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
482 if args:
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
483 m[b'error'][b'args'] = args
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
484
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
485 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
486
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
487 yield stream.makeframe(requestid=requestid,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
488 typeid=FRAME_TYPE_COMMAND_RESPONSE,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
489 flags=FLAG_COMMAND_RESPONSE_EOS,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
490 payload=overall)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
491
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
492 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
493 # 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
494 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
495
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
496 payload = b''.join(cborutil.streamencode({
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
497 b'type': errtype,
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
498 b'message': [{b'msg': msg}],
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
499 }))
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
500
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
501 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
502 typeid=FRAME_TYPE_ERROR_RESPONSE,
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
503 flags=0,
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
504 payload=payload)
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
505
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
506 def createtextoutputframe(stream, requestid, atoms,
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
507 maxframesize=DEFAULT_MAX_FRAME_SIZE):
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
508 """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
509
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
510 ``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
511
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
512 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
513 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
514 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
515 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
516 """
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
517 atomdicts = []
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
518
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
519 for (formatting, args, labels) in atoms:
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
520 # 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
521
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
522 if not isinstance(formatting, bytes):
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
523 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
524 for arg in args:
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
525 if not isinstance(arg, bytes):
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
526 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
527 for label in labels:
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
528 if not isinstance(label, bytes):
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
529 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
530
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
531 # Formatting string must be ASCII.
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
532 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
533
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
534 # Arguments must be UTF-8.
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
535 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
536
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
537 # Labels must be ASCII.
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
538 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
539 for l in labels]
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
540
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
541 atom = {b'msg': formatting}
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
542 if args:
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
543 atom[b'args'] = args
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
544 if labels:
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
545 atom[b'labels'] = labels
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
546
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
547 atomdicts.append(atom)
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
548
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
549 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
550
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
551 if len(payload) > maxframesize:
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
552 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
553
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
554 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
555 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
556 flags=0,
37319
36d17f37db91 wireproto: convert human output frames to CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37299
diff changeset
557 payload=payload)
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
558
39576
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
559 class bufferingcommandresponseemitter(object):
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
560 """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
561
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
562 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
563 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
564 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
565
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
566 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
567 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
568 level.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
569 """
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
570 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
571 self._stream = stream
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
572 self._requestid = requestid
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
573 self._maxsize = maxframesize
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
574 self._chunks = []
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
575 self._chunkssize = 0
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
576
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
577 def send(self, data):
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
578 """Send new data for emission.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
579
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
580 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
581
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
582 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
583 data to frames.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
584 """
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
585
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
586 if data is None:
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
587 for frame in self._flush():
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
588 yield frame
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
589 return
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
590
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
591 # 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
592 # 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
593 # 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
594 # a simple implementation:
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
595 #
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
596 # * 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
597 # for the new chunk.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
598 # * 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
599 # being exceeded, we do that.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
600 # * 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
601 # 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
602
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
603 if len(data) > self._maxsize:
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
604 for frame in self._flush():
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
605 yield frame
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
606
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
607 # 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
608 offset = 0
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
609 while True:
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
610 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
611 offset += len(chunk)
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 yield self._stream.makeframe(
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
614 self._requestid,
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
615 typeid=FRAME_TYPE_COMMAND_RESPONSE,
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
616 flags=FLAG_COMMAND_RESPONSE_CONTINUATION,
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
617 payload=chunk)
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
618
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
619 if offset == len(data):
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
620 return
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
621
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
622 # 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
623 # return.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
624 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
625 self._chunks.append(data)
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
626 self._chunkssize += len(data)
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
627 return
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
628
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
629 # 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
630 # 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
631 # keep things simple for now.
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
632 for frame in self._flush():
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
633 yield frame
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
634
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
635 self._chunks.append(data)
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
636 self._chunkssize = len(data)
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
637
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
638 def _flush(self):
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
639 payload = b''.join(self._chunks)
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
640 assert len(payload) <= self._maxsize
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
641
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
642 self._chunks[:] = []
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
643 self._chunkssize = 0
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
644
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
645 yield self._stream.makeframe(
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
646 self._requestid,
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
647 typeid=FRAME_TYPE_COMMAND_RESPONSE,
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
648 flags=FLAG_COMMAND_RESPONSE_CONTINUATION,
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
649 payload=payload)
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
650
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
651 # 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
652 # mechanism.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
653
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
654 class identityencoder(object):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
655 """Encoder for the "identity" stream encoding profile."""
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
656 def __init__(self, ui):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
657 pass
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
658
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
659 def encode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
660 return data
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
661
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
662 def flush(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
663 return b''
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
664
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
665 def finish(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
666 return b''
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
667
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
668 class identitydecoder(object):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
669 """Decoder for the "identity" stream encoding profile."""
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
670
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
671 def __init__(self, ui, extraobjs):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
672 if extraobjs:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
673 raise error.Abort(_('identity decoder received unexpected '
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
674 'additional values'))
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
675
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
676 def decode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
677 return data
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
678
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
679 class zlibencoder(object):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
680 def __init__(self, ui):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
681 import zlib
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
682 self._zlib = zlib
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
683 self._compressor = zlib.compressobj()
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 def encode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
686 return self._compressor.compress(data)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
687
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
688 def flush(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
689 # 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
690 # what we want.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
691 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
692
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
693 def finish(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
694 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
695 self._compressor = None
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
696 return res
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
697
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
698 class zlibdecoder(object):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
699 def __init__(self, ui, extraobjs):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
700 import zlib
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
701
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
702 if extraobjs:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
703 raise error.Abort(_('zlib decoder received unexpected '
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
704 'additional values'))
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 self._decompressor = zlib.decompressobj()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
707
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
708 def decode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
709 # 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
710 # handle all bytes-like types.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
711 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
712 data = bytes(data)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
713
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
714 return self._decompressor.decompress(data)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
715
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
716 class zstdbaseencoder(object):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
717 def __init__(self, level):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
718 from . import zstd
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
719
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
720 self._zstd = zstd
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
721 cctx = zstd.ZstdCompressor(level=level)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
722 self._compressor = cctx.compressobj()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
723
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
724 def encode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
725 return self._compressor.compress(data)
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 flush(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
728 # 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
729 # 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
730 # up to this point.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
731 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
732
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
733 def finish(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
734 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
735 self._compressor = None
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
736 return res
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 class zstd8mbencoder(zstdbaseencoder):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
739 def __init__(self, ui):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
740 super(zstd8mbencoder, self).__init__(3)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
741
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
742 class zstdbasedecoder(object):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
743 def __init__(self, maxwindowsize):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
744 from . import zstd
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
745 dctx = zstd.ZstdDecompressor(max_window_size=maxwindowsize)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
746 self._decompressor = dctx.decompressobj()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
747
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
748 def decode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
749 return self._decompressor.decompress(data)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
750
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
751 class zstd8mbdecoder(zstdbasedecoder):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
752 def __init__(self, ui, extraobjs):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
753 if extraobjs:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
754 raise error.Abort(_('zstd8mb decoder received unexpected '
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
755 'additional values'))
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
756
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
757 super(zstd8mbdecoder, self).__init__(maxwindowsize=8 * 1048576)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
758
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
759 # 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
760 # this module.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
761 STREAM_ENCODERS = {}
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
762 STREAM_ENCODERS_ORDER = []
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
763
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
764 def populatestreamencoders():
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
765 if STREAM_ENCODERS:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
766 return
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
767
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
768 try:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
769 from . import zstd
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
770 zstd.__version__
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
771 except ImportError:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
772 zstd = None
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
773
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
774 # zstandard is fastest and is preferred.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
775 if zstd:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
776 STREAM_ENCODERS[b'zstd-8mb'] = (zstd8mbencoder, zstd8mbdecoder)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
777 STREAM_ENCODERS_ORDER.append(b'zstd-8mb')
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
778
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
779 STREAM_ENCODERS[b'zlib'] = (zlibencoder, zlibdecoder)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
780 STREAM_ENCODERS_ORDER.append(b'zlib')
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
781
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
782 STREAM_ENCODERS[b'identity'] = (identityencoder, identitydecoder)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
783 STREAM_ENCODERS_ORDER.append(b'identity')
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
784
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
785 class stream(object):
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
786 """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
787
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
788 def __init__(self, streamid, active=False):
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
789 self.streamid = streamid
37655
b9502b5f2066 wireprotoframing: use value passed into function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37544
diff changeset
790 self._active = active
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
791
37287
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
792 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
793 """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
794
3ed344546d9e wireproto: start to associate frame generation with a stream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37087
diff changeset
795 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
796 """
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
797 streamflags = 0
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
798 if not self._active:
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
799 streamflags |= STREAM_FLAG_BEGIN_STREAM
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
800 self._active = True
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
801
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
802 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
803 payload)
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
804
40131
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
805 class inputstream(stream):
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
806 """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
807
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
808 def __init__(self, streamid, active=False):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
809 super(inputstream, self).__init__(streamid, active=active)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
810 self._decoder = None
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
811
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
812 def setdecoder(self, ui, name, extraobjs):
40129
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
813 """Set the decoder for this stream.
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
814
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
815 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
816 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
817 """
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
818 if name not in STREAM_ENCODERS:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
819 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
820
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
821 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
822
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
823 def decode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
824 # 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
825 # because it is trivial.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
826 if not self._decoder:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
827 return data
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
828
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
829 return self._decoder.decode(data)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
830
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
831 def flush(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
832 if not self._decoder:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
833 return b''
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
834
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
835 return self._decoder.flush()
40129
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
836
40131
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
837 class outputstream(stream):
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
838 """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
839
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
840 def __init__(self, streamid, active=False):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
841 super(outputstream, self).__init__(streamid, active=active)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
842 self._encoder = None
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
843
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
844 def setencoder(self, ui, name):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
845 """Set the encoder for this stream.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
846
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
847 Receives the stream profile name.
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
848 """
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
849 if name not in STREAM_ENCODERS:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
850 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
851
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
852 self._encoder = STREAM_ENCODERS[name][0](ui)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
853
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
854 def encode(self, data):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
855 if not self._encoder:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
856 return data
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
857
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
858 return self._encoder.encode(data)
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
859
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
860 def flush(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
861 if not self._encoder:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
862 return b''
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
863
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
864 return self._encoder.flush()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
865
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
866 def finish(self):
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
867 if not self._encoder:
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
868 return b''
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
869
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
870 self._encoder.finish()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
871
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
872 def ensureserverstream(stream):
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
873 if stream.streamid % 2:
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
874 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
875 'numbered streams; %d is not even' %
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
876 stream.streamid)
37063
0a6c5cc09a88 wireproto: define human output side channel frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37061
diff changeset
877
40127
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
878 DEFAULT_PROTOCOL_SETTINGS = {
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
879 'contentencodings': [b'identity'],
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
880 }
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
881
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
882 class serverreactor(object):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
883 """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
884
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
885 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
886 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
887 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
888 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
889
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
890 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
891 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
892 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
893 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
894 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
895 *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
896
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
897 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
898 this class.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
899
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
900 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
901 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
902 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
903 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
904 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
905 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
906 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
907
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
908 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
909
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
910 sendframes
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
911 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
912 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
913 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
914
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
915 error
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
916 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
917
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
918 runcommand
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
919 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
920 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
921
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
922 wantframe
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
923 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
924 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
925
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
926 noop
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
927 Indicates no additional action is required.
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
928
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
929 Known Issues
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
930 ------------
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
931
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
932 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
933 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
934 server's memory.
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
935
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
936 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
937 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
938 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
939 to facilitate graceful shutdown?
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
940
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
941 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
942 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
943 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
944 between who responds to what.
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
945 """
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
946
40130
293835e0fff7 wireprotov2: pass ui into clientreactor and serverreactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40129
diff changeset
947 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
948 """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
949
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
950 ``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
951 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
952 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
953 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
954 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
955 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
956 """
40130
293835e0fff7 wireprotov2: pass ui into clientreactor and serverreactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40129
diff changeset
957 self._ui = ui
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
958 self._deferoutput = deferoutput
40127
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
959 self._state = 'initial'
37289
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
960 self._nextoutgoingstreamid = 2
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
961 self._bufferedframegens = []
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
962 # 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
963 self._incomingstreams = {}
37289
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
964 self._outgoingstreams = {}
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
965 # 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
966 self._receivingcommands = {}
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
967 # 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
968 # 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
969 # set.
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
970 self._activecommands = set()
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
971
40127
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
972 self._protocolsettingsdecoder = None
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
973
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
974 # 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
975 self._sendersettings = dict(DEFAULT_PROTOCOL_SETTINGS)
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
976
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
977 populatestreamencoders()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
978
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
979 def onframerecv(self, frame):
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
980 """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
981
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
982 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
983 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
984 """
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
985 if not frame.streamid % 2:
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
986 self._state = 'errored'
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
987 return self._makeerrorresult(
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
988 _('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
989 frame.streamid)
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
990
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
991 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
992 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
993 self._state = 'errored'
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
994 return self._makeerrorresult(
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
995 _('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
996 'beginning of stream flag set'))
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
997
40131
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
998 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
999
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
1000 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
1001 # TODO handle decoding frames
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
1002 self._state = 'errored'
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
1003 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
1004 'not yet implemented')
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
1005
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
1006 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
1007 del self._incomingstreams[frame.streamid]
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
1008
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1009 handlers = {
40127
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1010 'initial': self._onframeinitial,
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1011 'protocol-settings-receiving': self._onframeprotocolsettings,
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1012 'idle': self._onframeidle,
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1013 'command-receiving': self._onframecommandreceiving,
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1014 'errored': self._onframeerrored,
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1015 }
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1016
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1017 meth = handlers.get(self._state)
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1018 if not meth:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1019 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
1020
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1021 return meth(frame)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1022
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
1023 def oncommandresponseready(self, stream, requestid, data):
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
1024 """Signal that a bytes response is ready to be sent to the client.
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
1025
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
1026 The raw bytes response is passed as an argument.
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
1027 """
37288
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
1028 ensureserverstream(stream)
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
1029
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1030 def sendframes():
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
1031 for frame in createcommandresponseframesfrombytes(stream, requestid,
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
1032 data):
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1033 yield frame
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1034
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1035 self._activecommands.remove(requestid)
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1036
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1037 result = sendframes()
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1038
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1039 if self._deferoutput:
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1040 self._bufferedframegens.append(result)
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1041 return 'noop', {}
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1042 else:
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1043 return 'sendframes', {
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1044 'framegen': result,
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1045 }
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1046
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1047 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
1048 """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
1049
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1050 ``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
1051 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
1052 client.
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1053 """
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1054 ensureserverstream(stream)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1055
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1056 # 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
1057 # 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
1058 # 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
1059 # in a bad state.
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1060 #
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1061 # 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
1062 # 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
1063 # 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
1064 # 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
1065 #
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1066 # 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
1067 # 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
1068
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1069 def sendframes():
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1070 emitted = False
40026
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1071 alternatelocationsent = False
39576
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
1072 emitter = bufferingcommandresponseemitter(stream, requestid)
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1073 while True:
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1074 try:
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1075 o = next(objs)
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1076 except StopIteration:
39576
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
1077 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
1078 yield frame
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
1079
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1080 if emitted:
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1081 yield createcommandresponseeosframe(stream, requestid)
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1082 break
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1083
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1084 except error.WireprotoCommandError as e:
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1085 for frame in createcommanderrorresponse(
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1086 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
1087 yield frame
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1088 break
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1089
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1090 except Exception as e:
39843
bce1c1af7518 py3: cast exception to bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39576
diff changeset
1091 for frame in createerrorframe(
bce1c1af7518 py3: cast exception to bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39576
diff changeset
1092 stream, requestid, '%s' % stringutil.forcebytestr(e),
bce1c1af7518 py3: cast exception to bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39576
diff changeset
1093 errtype='server'):
bce1c1af7518 py3: cast exception to bytes
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39576
diff changeset
1094
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1095 yield frame
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1096
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1097 break
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1098
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1099 try:
40026
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1100 # 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
1101 # only object in the output stream.
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1102 if isinstance(o, wireprototypes.alternatelocationresponse):
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1103 if emitted:
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1104 raise error.ProgrammingError(
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1105 'alternatelocationresponse seen after initial '
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1106 'output object')
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1107
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1108 yield createalternatelocationresponseframe(
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1109 stream, requestid, o)
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1110
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1111 alternatelocationsent = True
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1112 emitted = True
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1113 continue
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1114
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1115 if alternatelocationsent:
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1116 raise error.ProgrammingError(
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1117 'object follows alternatelocationresponse')
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1118
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1119 if not emitted:
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1120 yield createcommandresponseokframe(stream, requestid)
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1121 emitted = True
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1122
40021
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
1123 # 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
1124 # data structures or special types.
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
1125 # 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
1126 # 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
1127
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
1128 # 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
1129 if isinstance(o, wireprototypes.encodedresponse):
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
1130 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
1131 yield frame
84bf6ded9317 wireprotoframing: buffer emitted data to reduce frame count
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39575
diff changeset
1132
40021
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
1133 # 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
1134 else:
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
1135 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
1136 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
1137 yield frame
ed919b90acda wireprotov2: define type to represent pre-encoded object
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39843
diff changeset
1138
39575
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1139 except Exception as e:
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1140 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
1141 '%s' % e,
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1142 errtype='server'):
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1143 yield frame
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1144
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39503
diff changeset
1145 break
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1146
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1147 self._activecommands.remove(requestid)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1148
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1149 return self._handlesendframes(sendframes())
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1150
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1151 def oninputeof(self):
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1152 """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
1153
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1154 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
1155 completed.
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1156 """
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1157 # 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
1158
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1159 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
1160 return 'noop', {}
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1161
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1162 # 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
1163 def makegen():
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1164 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
1165 for frame in gen:
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1166 yield frame
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1167
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
1168 return 'sendframes', {
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
1169 'framegen': makegen(),
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
1170 }
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
1171
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1172 def _handlesendframes(self, framegen):
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1173 if self._deferoutput:
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1174 self._bufferedframegens.append(framegen)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1175 return 'noop', {}
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1176 else:
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1177 return 'sendframes', {
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1178 'framegen': framegen,
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1179 }
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1180
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1181 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
1182 ensureserverstream(stream)
9bfcbe4f4745 wireproto: add streams to frame-based protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37287
diff changeset
1183
37728
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1184 def sendframes():
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1185 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
1186 errtype='server'):
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1187 yield frame
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1188
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1189 self._activecommands.remove(requestid)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1190
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1191 return self._handlesendframes(sendframes())
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1192
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1193 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
1194 """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
1195 ensureserverstream(stream)
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1196
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1197 def sendframes():
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1198 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
1199 args):
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1200 yield frame
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1201
564a3eec6e63 wireprotov2: add support for more response types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37726
diff changeset
1202 self._activecommands.remove(requestid)
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 return self._handlesendframes(sendframes())
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37055
diff changeset
1205
37289
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
1206 def makeoutputstream(self):
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
1207 """Create a stream to be used for sending data to the client."""
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
1208 streamid = self._nextoutgoingstreamid
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
1209 self._nextoutgoingstreamid += 2
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
1210
40131
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
1211 s = outputstream(streamid)
37289
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
1212 self._outgoingstreams[streamid] = s
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
1213
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
1214 return s
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
1215
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1216 def _makeerrorresult(self, msg):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1217 return 'error', {
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1218 'message': msg,
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1219 }
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1220
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1221 def _makeruncommandresult(self, requestid):
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1222 entry = self._receivingcommands[requestid]
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1223
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1224 if not entry['requestdone']:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1225 self._state = 'errored'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1226 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
1227 'requestdone set')
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1228
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1229 del self._receivingcommands[requestid]
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1230
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1231 if self._receivingcommands:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1232 self._state = 'command-receiving'
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1233 else:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1234 self._state = 'idle'
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1235
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1236 # Decode the payloads as CBOR.
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1237 entry['payload'].seek(0)
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
1238 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
1239
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1240 if b'name' not in request:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1241 self._state = 'errored'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1242 return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1243 _('command request missing "name" field'))
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1244
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1245 if b'args' not in request:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1246 request[b'args'] = {}
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1247
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1248 assert requestid not in self._activecommands
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1249 self._activecommands.add(requestid)
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1250
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1251 return 'runcommand', {
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1252 'requestid': requestid,
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1253 'command': request[b'name'],
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1254 'args': request[b'args'],
40026
b099e6032f38 wireprotov2: server support for sending content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40025
diff changeset
1255 'redirect': request.get(b'redirect'),
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1256 '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
1257 }
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1258
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1259 def _makewantframeresult(self):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1260 return 'wantframe', {
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1261 'state': self._state,
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1262 }
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1263
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1264 def _validatecommandrequestframe(self, frame):
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1265 new = frame.flags & FLAG_COMMAND_REQUEST_NEW
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1266 continuation = frame.flags & FLAG_COMMAND_REQUEST_CONTINUATION
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1267
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1268 if new and continuation:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1269 self._state = 'errored'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1270 return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1271 _('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
1272 'continuation flags set'))
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1273
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1274 if not new and not continuation:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1275 self._state = 'errored'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1276 return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1277 _('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
1278 'continuation flags set'))
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1279
40127
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1280 def _onframeinitial(self, frame):
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1281 # 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
1282 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
1283 self._state = 'protocol-settings-receiving'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1284 self._protocolsettingsdecoder = cborutil.bufferingdecoder()
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1285 return self._onframeprotocolsettings(frame)
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1286
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1287 elif frame.typeid == FRAME_TYPE_COMMAND_REQUEST:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1288 self._state = 'idle'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1289 return self._onframeidle(frame)
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1290
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1291 else:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1292 self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1293 return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1294 _('expected sender protocol settings or command request '
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1295 'frame; got %d') % frame.typeid)
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1296
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1297 def _onframeprotocolsettings(self, frame):
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1298 assert self._state == 'protocol-settings-receiving'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1299 assert self._protocolsettingsdecoder is not None
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1300
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1301 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
1302 self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1303 return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1304 _('expected sender protocol settings frame; got %d') %
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1305 frame.typeid)
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1306
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1307 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
1308 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
1309
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1310 if more and eos:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1311 self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1312 return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1313 _('sender protocol settings frame cannot have both '
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1314 'continuation and end of stream flags set'))
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1315
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1316 if not more and not eos:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1317 self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1318 return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1319 _('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
1320 'end of stream flag set'))
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1321
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1322 # 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
1323 # buffered.
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1324 try:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1325 self._protocolsettingsdecoder.decode(frame.payload)
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1326 except Exception as e:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1327 self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1328 return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1329 _('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
1330 % stringutil.forcebytestr(e))
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1331
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1332 if more:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1333 return self._makewantframeresult()
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1334
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1335 assert eos
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 decoded = self._protocolsettingsdecoder.getavailable()
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1338 self._protocolsettingsdecoder = None
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1339
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1340 if not decoded:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1341 self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1342 return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1343 _('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
1344 elif len(decoded) > 1:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1345 self._state = 'errored'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1346 return self._makeerrorresult(
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1347 _('sender protocol settings frame contained multiple CBOR '
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1348 'values'))
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1349
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1350 d = decoded[0]
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 b'contentencodings' in d:
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1353 self._sendersettings['contentencodings'] = d[b'contentencodings']
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1354
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1355 self._state = 'idle'
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1356
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1357 return self._makewantframeresult()
327d40b94bed wireprotov2: handle sender protocol settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40126
diff changeset
1358
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1359 def _onframeidle(self, frame):
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1360 # 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
1361 # command request.
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1362 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
1363 self._state = 'errored'
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1364 return self._makeerrorresult(
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1365 _('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
1366
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1367 res = self._validatecommandrequestframe(frame)
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1368 if res:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1369 return res
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1370
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1371 if frame.requestid in self._receivingcommands:
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1372 self._state = 'errored'
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1373 return self._makeerrorresult(
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1374 _('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
1375
37066
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1376 if frame.requestid in self._activecommands:
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1377 self._state = 'errored'
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1378 return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1379 _('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
1380
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1381 new = frame.flags & FLAG_COMMAND_REQUEST_NEW
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1382 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
1383 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
1384
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1385 if not new:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1386 self._state = 'errored'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1387 return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1388 _('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
1389
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1390 payload = util.bytesio()
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1391 payload.write(frame.payload)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1392
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1393 self._receivingcommands[frame.requestid] = {
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1394 'payload': payload,
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1395 'data': None,
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1396 'requestdone': not moreframes,
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1397 'expectingdata': bool(expectingdata),
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1398 }
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1399
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1400 # 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
1401 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
1402 return self._makeruncommandresult(frame.requestid)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1403
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1404 assert moreframes or expectingdata
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1405 self._state = 'command-receiving'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1406 return self._makewantframeresult()
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1407
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1408 def _onframecommandreceiving(self, frame):
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1409 if frame.typeid == FRAME_TYPE_COMMAND_REQUEST:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1410 # Process new command requests as such.
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1411 if frame.flags & FLAG_COMMAND_REQUEST_NEW:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1412 return self._onframeidle(frame)
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1413
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1414 res = self._validatecommandrequestframe(frame)
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1415 if res:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1416 return res
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1417
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1418 # 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
1419 # receiving but is not active.
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1420 if frame.requestid in self._activecommands:
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1421 self._state = 'errored'
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1422 return self._makeerrorresult(
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1423 _('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
1424 frame.requestid)
39304dd63589 wireproto: explicitly track which requests are active
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37065
diff changeset
1425
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1426 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
1427 self._state = 'errored'
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1428 return self._makeerrorresult(
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1429 _('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
1430 frame.requestid)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1431
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1432 entry = self._receivingcommands[frame.requestid]
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1433
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1434 if frame.typeid == FRAME_TYPE_COMMAND_REQUEST:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1435 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
1436 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
1437
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1438 if entry['requestdone']:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1439 self._state = 'errored'
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1440 return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1441 _('received command request frame when request frames '
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1442 'were supposedly done'))
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1443
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1444 if expectingdata != entry['expectingdata']:
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1445 self._state = 'errored'
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1446 return self._makeerrorresult(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1447 _('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
1448
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1449 entry['payload'].write(frame.payload)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1450
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1451 if not moreframes:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1452 entry['requestdone'] = True
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1453
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1454 if not moreframes and not expectingdata:
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1455 return self._makeruncommandresult(frame.requestid)
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1456
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1457 return self._makewantframeresult()
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1458
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1459 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
1460 if not entry['expectingdata']:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1461 self._state = 'errored'
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1462 return self._makeerrorresult(_(
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1463 '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
1464 'expecting data: %d') % frame.requestid)
37061
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1465
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1466 if entry['data'] is None:
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1467 entry['data'] = util.bytesio()
c5e9c3b47366 wireproto: support for receiving multiple requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
1468
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1469 return self._handlecommanddataframe(frame, entry)
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1470 else:
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1471 self._state = 'errored'
37292
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1472 return self._makeerrorresult(_(
3d0e2cd86e05 wireproto: use CBOR for command requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37291
diff changeset
1473 '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
1474
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1475 def _handlecommanddataframe(self, frame, entry):
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1476 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
1477
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1478 # 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
1479 entry['data'].write(frame.payload)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1480
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1481 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
1482 return self._makewantframeresult()
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1483 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
1484 entry['data'].seek(0)
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1485 return self._makeruncommandresult(frame.requestid)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1486 else:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1487 self._state = 'errored'
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1488 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
1489 'flags'))
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1490
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37063
diff changeset
1491 def _onframeerrored(self, frame):
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
1492 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
1493
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1494 class commandrequest(object):
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1495 """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
1496
40025
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
1497 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
1498 self.requestid = requestid
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1499 self.name = name
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1500 self.args = args
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1501 self.datafh = datafh
40025
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
1502 self.redirect = redirect
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1503 self.state = 'pending'
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1504
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1505 class clientreactor(object):
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1506 """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
1507
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1508 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
1509
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1510 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
1511 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
1512 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
1513 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
1514 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
1515 separate instance for each distinct interaction.
40128
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1516
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1517 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
1518 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
1519 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
1520 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
1521 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
1522 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
1523 to those frames.
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1524
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1525 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
1526
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1527 noop
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1528 Indicates no additional action is required.
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1529
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1530 sendframes
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1531 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
1532 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
1533 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
1534
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1535 error
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1536 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
1537 error message describing the failure.
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1538
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1539 responsedata
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1540 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
1541
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1542 The ``request`` key contains the ``commandrequest`` instance that
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1543 represents the request this data is for.
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1544
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1545 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
1546
080419fa4fe4 wireprotov2: document client reactor actions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40127
diff changeset
1547 ``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
1548 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
1549 respectively.
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1550 """
40133
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1551 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
1552 clientcontentencoders=None):
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1553 """Create a new instance.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1554
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1555 ``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
1556 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
1557 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
1558 send operation.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1559
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1560 ``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
1561 last request has been issued.
40133
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1562
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1563 ``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
1564 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
1565 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
1566 to the server.
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1567 """
40130
293835e0fff7 wireprotov2: pass ui into clientreactor and serverreactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40129
diff changeset
1568 self._ui = ui
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1569 self._hasmultiplesend = hasmultiplesend
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1570 self._buffersends = buffersends
40133
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1571 self._clientcontentencoders = clientcontentencoders
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1572
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1573 self._canissuecommands = True
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1574 self._cansend = True
40133
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1575 self._protocolsettingssent = False
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1576
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1577 self._nextrequestid = 1
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1578 # 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
1579 self._outgoingstream = outputstream(1)
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1580 self._pendingrequests = collections.deque()
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1581 self._activerequests = {}
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1582 self._incomingstreams = {}
40129
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1583 self._streamsettingsdecoders = {}
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1584
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
1585 populatestreamencoders()
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
1586
40025
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
1587 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
1588 """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
1589
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1590 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
1591 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
1592
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1593 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
1594 """
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1595 if not self._canissuecommands:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1596 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
1597
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1598 requestid = self._nextrequestid
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1599 self._nextrequestid += 2
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1600
40025
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
1601 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
1602 redirect=redirect)
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1603
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1604 if self._buffersends:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1605 self._pendingrequests.append(request)
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1606 return request, 'noop', {}
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1607 else:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1608 if not self._cansend:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1609 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
1610 'this instance')
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1611
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1612 if not self._hasmultiplesend:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1613 self._cansend = False
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1614 self._canissuecommands = False
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1615
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1616 return request, 'sendframes', {
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1617 'framegen': self._makecommandframes(request),
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1618 }
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1619
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1620 def flushcommands(self):
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1621 """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
1622
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1623 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
1624 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
1625 to no-op.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1626
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1627 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
1628 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
1629 """
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1630 if not self._pendingrequests:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1631 return 'noop', {}
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1632
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1633 if not self._cansend:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1634 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
1635 'instance')
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1636
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1637 # 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
1638 # our one shot.
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1639 if not self._hasmultiplesend:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1640 self._canissuecommands = False
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1641 self._cansend = False
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1642
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1643 def makeframes():
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1644 while self._pendingrequests:
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1645 request = self._pendingrequests.popleft()
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1646 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
1647 yield frame
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1648
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1649 return 'sendframes', {
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1650 'framegen': makeframes(),
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
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1653 def _makecommandframes(self, request):
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1654 """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
1655
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1656 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
1657 state.
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 self._activerequests[request.requestid] = request
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1660 request.state = 'sending'
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1661
40133
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1662 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
1663 self._protocolsettingssent = True
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1664
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1665 payload = b''.join(cborutil.streamencode({
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1666 b'contentencodings': self._clientcontentencoders,
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1667 }))
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1668
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1669 yield self._outgoingstream.makeframe(
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1670 requestid=request.requestid,
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1671 typeid=FRAME_TYPE_SENDER_PROTOCOL_SETTINGS,
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1672 flags=FLAG_SENDER_PROTOCOL_SETTINGS_EOS,
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1673 payload=payload)
762ef19a07e3 wireprotov2: send protocol settings frame from client
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40132
diff changeset
1674
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1675 res = createcommandframes(self._outgoingstream,
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1676 request.requestid,
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1677 request.name,
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1678 request.args,
40025
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
1679 datafh=request.datafh,
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40021
diff changeset
1680 redirect=request.redirect)
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1681
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37485
diff changeset
1682 for frame in res:
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 request.state = 'sent'
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1686
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1687 def onframerecv(self, frame):
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1688 """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
1689
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1690 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
1691 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
1692 """
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1693 if frame.streamid % 2:
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1694 return 'error', {
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1695 'message': (
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1696 _('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
1697 frame.streamid),
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1698 }
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1699
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1700 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
1701 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
1702 return 'error', {
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1703 'message': _('received frame on unknown stream '
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1704 'without beginning of stream flag set'),
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1705 }
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1706
40131
5d44c4d1d516 wireprotov2: establish dedicated classes for input and output streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40130
diff changeset
1707 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
1708 frame.streamid)
37656
e6870bca1f47 wireprotoframing: record when new stream is encountered
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37655
diff changeset
1709
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
1710 stream = self._incomingstreams[frame.streamid]
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
1711
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
1712 # 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
1713 # 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
1714 # 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
1715 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
1716 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
1717
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1718 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
1719 del self._incomingstreams[frame.streamid]
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1720
40129
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1721 if frame.typeid == FRAME_TYPE_STREAM_SETTINGS:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1722 return self._onstreamsettingsframe(frame)
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1723
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1724 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
1725 return 'error', {
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1726 '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
1727 frame.requestid),
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
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1730 request = self._activerequests[frame.requestid]
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1731 request.state = 'receiving'
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1732
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1733 handlers = {
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
1734 FRAME_TYPE_COMMAND_RESPONSE: self._oncommandresponseframe,
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1735 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
1736 }
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1737
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1738 meth = handlers.get(frame.typeid)
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1739 if not meth:
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1740 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
1741 frame.typeid)
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1742
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1743 return meth(request, frame)
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1744
40129
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1745 def _onstreamsettingsframe(self, frame):
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1746 assert frame.typeid == FRAME_TYPE_STREAM_SETTINGS
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1747
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1748 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
1749 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
1750
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1751 if more and eos:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1752 return 'error', {
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1753 '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
1754 'continuation and end of stream flags set')),
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1755 }
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1756
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1757 if not more and not eos:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1758 return 'error', {
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1759 'message': _('stream encoding settings frame must have '
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1760 'continuation or end of stream flag set'),
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1761 }
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1762
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1763 if frame.streamid not in self._streamsettingsdecoders:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1764 decoder = cborutil.bufferingdecoder()
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1765 self._streamsettingsdecoders[frame.streamid] = decoder
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1766
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1767 decoder = self._streamsettingsdecoders[frame.streamid]
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1768
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1769 try:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1770 decoder.decode(frame.payload)
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1771 except Exception as e:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1772 return 'error', {
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1773 'message': (_('error decoding CBOR from stream encoding '
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1774 'settings frame: %s') %
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1775 stringutil.forcebytestr(e)),
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1776 }
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1777
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1778 if more:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1779 return 'noop', {}
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1780
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1781 assert eos
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1782
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1783 decoded = decoder.getavailable()
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1784 del self._streamsettingsdecoders[frame.streamid]
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1785
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1786 if not decoded:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1787 return 'error', {
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1788 '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
1789 'CBOR data'),
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1790 }
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 try:
40132
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
1793 self._incomingstreams[frame.streamid].setdecoder(self._ui,
e67522413ca8 wireprotov2: define and use stream encoders
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40131
diff changeset
1794 decoded[0],
40129
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1795 decoded[1:])
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1796 except Exception as e:
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1797 return 'error', {
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1798 'message': (_('error setting stream decoder: %s') %
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1799 stringutil.forcebytestr(e)),
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1800 }
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1801
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1802 return 'noop', {}
57782791b7e9 wireprotov2: handle stream encoding settings frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40128
diff changeset
1803
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
1804 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
1805 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
1806 request.state = 'received'
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1807 del self._activerequests[request.requestid]
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1808
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1809 return 'responsedata', {
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1810 'request': request,
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37723
diff changeset
1811 '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
1812 '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
1813 'data': frame.payload,
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
1814 }
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1815
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1816 def _onerrorresponseframe(self, request, frame):
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1817 request.state = 'errored'
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1818 del self._activerequests[request.requestid]
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1819
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1820 # The payload should be a CBOR map.
39465
36f487a332ad wireprotoframing: use our CBOR module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37728
diff changeset
1821 m = cborutil.decodeall(frame.payload)[0]
37726
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1822
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1823 return 'error', {
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1824 'request': request,
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1825 'type': m['type'],
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1826 'message': m['message'],
0c184ca594bb wireprotov2: change behavior of error frame
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37725
diff changeset
1827 }