annotate mercurial/wireprotov2peer.py @ 40024:86b22a4cfab1

wireprotov2: client support for advertising redirect targets With the server now able to emit a redirect target descriptor, we can start to teach the client to recognize it. This commit implements support for filtering the advertised redirect targets against supported features and for advertising compatible redirect targets as part of command requests. It also adds the minimal boilerplate required to fail when a content redirect is seen. The server doesn't yet do anything with the advertised redirect targets. And the client can't yet follow redirects if it did. But at least we're putting bytes on the wire. Differential Revision: https://phab.mercurial-scm.org/D4776
author Gregory Szorc <gregory.szorc@gmail.com>
date Wed, 26 Sep 2018 15:02:19 -0700
parents f5a05bb48116
children 7e807b8a9e56
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
1 # wireprotov2peer.py - client side code for wire protocol version 2
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
2 #
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
3 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
4 #
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
5 # This software may be used and distributed according to the terms of the
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
6 # GNU General Public License version 2 or any later version.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
7
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
8 from __future__ import absolute_import
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
9
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
10 import threading
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
11
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
12 from .i18n import _
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
13 from . import (
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
14 encoding,
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
15 error,
40024
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
16 sslutil,
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
17 wireprotoframing,
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
18 )
39450
9f51fd22ed50 wireprotov2peer: use our CBOR decoder
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39438
diff changeset
19 from .utils import (
9f51fd22ed50 wireprotov2peer: use our CBOR decoder
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39438
diff changeset
20 cborutil,
9f51fd22ed50 wireprotov2peer: use our CBOR decoder
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39438
diff changeset
21 )
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
22
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
23 def formatrichmessage(atoms):
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
24 """Format an encoded message from the framing protocol."""
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
25
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
26 chunks = []
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
27
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
28 for atom in atoms:
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
29 msg = _(atom[b'msg'])
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
30
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
31 if b'args' in atom:
39486
43d92d68ac88 wireprotov2peer: properly format errors
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39485
diff changeset
32 msg = msg % tuple(atom[b'args'])
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
33
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
34 chunks.append(msg)
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
35
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
36 return b''.join(chunks)
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
37
40024
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
38 SUPPORTED_REDIRECT_PROTOCOLS = {
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
39 b'http',
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
40 b'https',
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
41 }
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
42
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
43 SUPPORTED_CONTENT_HASHES = {
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
44 b'sha1',
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
45 b'sha256',
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
46 }
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
47
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
48 def redirecttargetsupported(ui, target):
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
49 """Determine whether a redirect target entry is supported.
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
50
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
51 ``target`` should come from the capabilities data structure emitted by
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
52 the server.
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
53 """
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
54 if target.get(b'protocol') not in SUPPORTED_REDIRECT_PROTOCOLS:
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
55 ui.note(_('(remote redirect target %s uses unsupported protocol: %s)\n')
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
56 % (target[b'name'], target.get(b'protocol', b'')))
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
57 return False
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
58
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
59 if target.get(b'snirequired') and not sslutil.hassni:
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
60 ui.note(_('(redirect target %s requires SNI, which is unsupported)\n') %
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
61 target[b'name'])
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
62 return False
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
63
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
64 if b'tlsversions' in target:
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
65 tlsversions = set(target[b'tlsversions'])
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
66 supported = set()
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
67
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
68 for v in sslutil.supportedprotocols:
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
69 assert v.startswith(b'tls')
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
70 supported.add(v[3:])
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
71
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
72 if not tlsversions & supported:
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
73 ui.note(_('(remote redirect target %s requires unsupported TLS '
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
74 'versions: %s)\n') % (
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
75 target[b'name'], b', '.join(sorted(tlsversions))))
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
76 return False
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
77
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
78 ui.note(_('(remote redirect target %s is compatible)\n') % target[b'name'])
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
79
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
80 return True
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
81
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
82 def supportedredirects(ui, apidescriptor):
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
83 """Resolve the "redirect" command request key given an API descriptor.
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
84
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
85 Given an API descriptor returned by the server, returns a data structure
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
86 that can be used in hte "redirect" field of command requests to advertise
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
87 support for compatible redirect targets.
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
88
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
89 Returns None if no redirect targets are remotely advertised or if none are
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
90 supported.
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
91 """
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
92 if not apidescriptor or b'redirect' not in apidescriptor:
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
93 return None
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
94
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
95 targets = [t[b'name'] for t in apidescriptor[b'redirect'][b'targets']
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
96 if redirecttargetsupported(ui, t)]
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
97
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
98 hashes = [h for h in apidescriptor[b'redirect'][b'hashes']
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
99 if h in SUPPORTED_CONTENT_HASHES]
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
100
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
101 return {
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
102 b'targets': targets,
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
103 b'hashes': hashes,
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
104 }
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
105
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
106 class commandresponse(object):
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
107 """Represents the response to a command request.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
108
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
109 Instances track the state of the command and hold its results.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
110
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
111 An external entity is required to update the state of the object when
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
112 events occur.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
113 """
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
114
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
115 def __init__(self, requestid, command):
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
116 self.requestid = requestid
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
117 self.command = command
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
118
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
119 # Whether all remote input related to this command has been
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
120 # received.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
121 self._inputcomplete = False
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
122
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
123 # We have a lock that is acquired when important object state is
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
124 # mutated. This is to prevent race conditions between 1 thread
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
125 # sending us new data and another consuming it.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
126 self._lock = threading.RLock()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
127
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
128 # An event is set when state of the object changes. This event
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
129 # is waited on by the generator emitting objects.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
130 self._serviceable = threading.Event()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
131
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
132 self._pendingevents = []
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
133 self._decoder = cborutil.bufferingdecoder()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
134 self._seeninitial = False
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
135
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
136 def _oninputcomplete(self):
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
137 with self._lock:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
138 self._inputcomplete = True
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
139 self._serviceable.set()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
140
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
141 def _onresponsedata(self, data):
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
142 available, readcount, wanted = self._decoder.decode(data)
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
143
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
144 if not available:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
145 return
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
146
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
147 with self._lock:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
148 for o in self._decoder.getavailable():
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
149 if not self._seeninitial:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
150 self._handleinitial(o)
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
151 continue
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
152
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
153 self._pendingevents.append(o)
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
154
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
155 self._serviceable.set()
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
156
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
157 def _handleinitial(self, o):
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
158 self._seeninitial = True
40024
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
159 if o[b'status'] == b'ok':
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
160 return
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
161
40024
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
162 elif o[b'status'] == b'redirect':
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
163 raise error.Abort(_('redirect responses not yet supported'))
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
164
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
165 atoms = [{'msg': o[b'error'][b'message']}]
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
166 if b'args' in o[b'error']:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
167 atoms[0]['args'] = o[b'error'][b'args']
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
168
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
169 raise error.RepoError(formatrichmessage(atoms))
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
170
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
171 def objects(self):
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
172 """Obtained decoded objects from this response.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
173
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
174 This is a generator of data structures that were decoded from the
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
175 command response.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
176
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
177 Obtaining the next member of the generator may block due to waiting
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
178 on external data to become available.
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
179
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
180 If the server encountered an error in the middle of serving the data
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
181 or if another error occurred, an exception may be raised when
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
182 advancing the generator.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
183 """
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
184 while True:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
185 # TODO this can infinite loop if self._inputcomplete is never
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
186 # set. We likely want to tie the lifetime of this object/state
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
187 # to that of the background thread receiving frames and updating
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
188 # our state.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
189 self._serviceable.wait(1.0)
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
190
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
191 with self._lock:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
192 self._serviceable.clear()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
193
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
194 # Make copies because objects could be mutated during
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
195 # iteration.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
196 stop = self._inputcomplete
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
197 pending = list(self._pendingevents)
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
198 self._pendingevents[:] = []
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
199
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
200 for o in pending:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
201 yield o
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
202
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
203 if stop:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
204 break
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
205
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
206 class clienthandler(object):
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
207 """Object to handle higher-level client activities.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
208
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
209 The ``clientreactor`` is used to hold low-level state about the frame-based
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
210 protocol, such as which requests and streams are active. This type is used
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
211 for higher-level operations, such as reading frames from a socket, exposing
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
212 and managing a higher-level primitive for representing command responses,
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
213 etc. This class is what peers should probably use to bridge wire activity
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
214 with the higher-level peer API.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
215 """
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
216
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
217 def __init__(self, ui, clientreactor):
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
218 self._ui = ui
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
219 self._reactor = clientreactor
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
220 self._requests = {}
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
221 self._futures = {}
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
222 self._responses = {}
40019
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
223 self._frameseof = False
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
224
40024
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
225 def callcommand(self, command, args, f, redirect=None):
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
226 """Register a request to call a command.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
227
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
228 Returns an iterable of frames that should be sent over the wire.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
229 """
40024
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
230 request, action, meta = self._reactor.callcommand(command, args,
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
231 redirect=redirect)
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
232
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
233 if action != 'noop':
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
234 raise error.ProgrammingError('%s not yet supported' % action)
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
235
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
236 rid = request.requestid
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
237 self._requests[rid] = request
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
238 self._futures[rid] = f
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
239 # TODO we need some kind of lifetime on response instances otherwise
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
240 # objects() may deadlock.
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
241 self._responses[rid] = commandresponse(rid, command)
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
242
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
243 return iter(())
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
244
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
245 def flushcommands(self):
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
246 """Flush all queued commands.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
247
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
248 Returns an iterable of frames that should be sent over the wire.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
249 """
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
250 action, meta = self._reactor.flushcommands()
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
251
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
252 if action != 'sendframes':
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
253 raise error.ProgrammingError('%s not yet supported' % action)
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
254
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
255 return meta['framegen']
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
256
40019
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
257 def readdata(self, framefh):
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
258 """Attempt to read data and do work.
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
259
40019
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
260 Returns None if no data was read. Presumably this means we're
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
261 done with all read I/O.
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
262 """
40019
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
263 if not self._frameseof:
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
264 frame = wireprotoframing.readframe(framefh)
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
265 if frame is None:
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
266 # TODO tell reactor?
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
267 self._frameseof = True
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
268 else:
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
269 self._ui.note(_('received %r\n') % frame)
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
270 self._processframe(frame)
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
271
40019
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
272 if self._frameseof:
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
273 return None
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
274
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
275 return True
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
276
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
277 def _processframe(self, frame):
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
278 """Process a single read frame."""
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
279
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
280 action, meta = self._reactor.onframerecv(frame)
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
281
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
282 if action == 'error':
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
283 e = error.RepoError(meta['message'])
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
284
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
285 if frame.requestid in self._responses:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
286 self._responses[frame.requestid]._oninputcomplete()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
287
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
288 if frame.requestid in self._futures:
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
289 self._futures[frame.requestid].set_exception(e)
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
290 del self._futures[frame.requestid]
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
291 else:
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
292 raise e
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
293
39559
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39486
diff changeset
294 return
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39486
diff changeset
295
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
296 if frame.requestid not in self._requests:
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
297 raise error.ProgrammingError(
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
298 'received frame for unknown request; this is either a bug in '
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
299 'the clientreactor not screening for this or this instance was '
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
300 'never told about this request: %r' % frame)
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
301
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
302 response = self._responses[frame.requestid]
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
303
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
304 if action == 'responsedata':
39485
42bc1c70a6b8 wireprotov2peer: report exceptions in frame handling against request future
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39450
diff changeset
305 # Any failures processing this frame should bubble up to the
42bc1c70a6b8 wireprotov2peer: report exceptions in frame handling against request future
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39450
diff changeset
306 # future tracking the request.
42bc1c70a6b8 wireprotov2peer: report exceptions in frame handling against request future
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39450
diff changeset
307 try:
42bc1c70a6b8 wireprotov2peer: report exceptions in frame handling against request future
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39450
diff changeset
308 self._processresponsedata(frame, meta, response)
42bc1c70a6b8 wireprotov2peer: report exceptions in frame handling against request future
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39450
diff changeset
309 except BaseException as e:
42bc1c70a6b8 wireprotov2peer: report exceptions in frame handling against request future
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39450
diff changeset
310 self._futures[frame.requestid].set_exception(e)
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
311 del self._futures[frame.requestid]
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
312 response._oninputcomplete()
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
313 else:
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
314 raise error.ProgrammingError(
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
315 'unhandled action from clientreactor: %s' % action)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
316
39438
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
317 def _processresponsedata(self, frame, meta, response):
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
318 # This can raise. The caller can handle it.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
319 response._onresponsedata(meta['data'])
39438
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
320
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
321 if meta['eos']:
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
322 response._oninputcomplete()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
323 del self._requests[frame.requestid]
39438
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
324
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
325 # If the command has a decoder, we wait until all input has been
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
326 # received before resolving the future. Otherwise we resolve the
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
327 # future immediately.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
328 if frame.requestid not in self._futures:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
329 return
39438
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
330
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
331 if response.command not in COMMAND_DECODERS:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
332 self._futures[frame.requestid].set_result(response.objects())
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
333 del self._futures[frame.requestid]
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
334 elif response._inputcomplete:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
335 decoded = COMMAND_DECODERS[response.command](response.objects())
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
336 self._futures[frame.requestid].set_result(decoded)
39438
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
337 del self._futures[frame.requestid]
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
338
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
339 def decodebranchmap(objs):
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
340 # Response should be a single CBOR map of branch name to array of nodes.
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
341 bm = next(objs)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
342
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
343 return {encoding.tolocal(k): v for k, v in bm.items()}
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
344
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
345 def decodeheads(objs):
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
346 # Array of node bytestrings.
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
347 return next(objs)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
348
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
349 def decodeknown(objs):
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
350 # Bytestring where each byte is a 0 or 1.
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
351 raw = next(objs)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
352
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
353 return [True if c == '1' else False for c in raw]
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
354
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
355 def decodelistkeys(objs):
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
356 # Map with bytestring keys and values.
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
357 return next(objs)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
358
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
359 def decodelookup(objs):
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
360 return next(objs)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
361
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
362 def decodepushkey(objs):
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
363 return next(objs)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
364
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
365 COMMAND_DECODERS = {
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
366 'branchmap': decodebranchmap,
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
367 'heads': decodeheads,
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
368 'known': decodeknown,
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
369 'listkeys': decodelistkeys,
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
370 'lookup': decodelookup,
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
371 'pushkey': decodepushkey,
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
372 }