xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/asyncio/protocols.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Abstract Protocol base classes."""
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard Worker__all__ = (
4*cda5da8dSAndroid Build Coastguard Worker    'BaseProtocol', 'Protocol', 'DatagramProtocol',
5*cda5da8dSAndroid Build Coastguard Worker    'SubprocessProtocol', 'BufferedProtocol',
6*cda5da8dSAndroid Build Coastguard Worker)
7*cda5da8dSAndroid Build Coastguard Worker
8*cda5da8dSAndroid Build Coastguard Worker
9*cda5da8dSAndroid Build Coastguard Workerclass BaseProtocol:
10*cda5da8dSAndroid Build Coastguard Worker    """Common base class for protocol interfaces.
11*cda5da8dSAndroid Build Coastguard Worker
12*cda5da8dSAndroid Build Coastguard Worker    Usually user implements protocols that derived from BaseProtocol
13*cda5da8dSAndroid Build Coastguard Worker    like Protocol or ProcessProtocol.
14*cda5da8dSAndroid Build Coastguard Worker
15*cda5da8dSAndroid Build Coastguard Worker    The only case when BaseProtocol should be implemented directly is
16*cda5da8dSAndroid Build Coastguard Worker    write-only transport like write pipe
17*cda5da8dSAndroid Build Coastguard Worker    """
18*cda5da8dSAndroid Build Coastguard Worker
19*cda5da8dSAndroid Build Coastguard Worker    __slots__ = ()
20*cda5da8dSAndroid Build Coastguard Worker
21*cda5da8dSAndroid Build Coastguard Worker    def connection_made(self, transport):
22*cda5da8dSAndroid Build Coastguard Worker        """Called when a connection is made.
23*cda5da8dSAndroid Build Coastguard Worker
24*cda5da8dSAndroid Build Coastguard Worker        The argument is the transport representing the pipe connection.
25*cda5da8dSAndroid Build Coastguard Worker        To receive data, wait for data_received() calls.
26*cda5da8dSAndroid Build Coastguard Worker        When the connection is closed, connection_lost() is called.
27*cda5da8dSAndroid Build Coastguard Worker        """
28*cda5da8dSAndroid Build Coastguard Worker
29*cda5da8dSAndroid Build Coastguard Worker    def connection_lost(self, exc):
30*cda5da8dSAndroid Build Coastguard Worker        """Called when the connection is lost or closed.
31*cda5da8dSAndroid Build Coastguard Worker
32*cda5da8dSAndroid Build Coastguard Worker        The argument is an exception object or None (the latter
33*cda5da8dSAndroid Build Coastguard Worker        meaning a regular EOF is received or the connection was
34*cda5da8dSAndroid Build Coastguard Worker        aborted or closed).
35*cda5da8dSAndroid Build Coastguard Worker        """
36*cda5da8dSAndroid Build Coastguard Worker
37*cda5da8dSAndroid Build Coastguard Worker    def pause_writing(self):
38*cda5da8dSAndroid Build Coastguard Worker        """Called when the transport's buffer goes over the high-water mark.
39*cda5da8dSAndroid Build Coastguard Worker
40*cda5da8dSAndroid Build Coastguard Worker        Pause and resume calls are paired -- pause_writing() is called
41*cda5da8dSAndroid Build Coastguard Worker        once when the buffer goes strictly over the high-water mark
42*cda5da8dSAndroid Build Coastguard Worker        (even if subsequent writes increases the buffer size even
43*cda5da8dSAndroid Build Coastguard Worker        more), and eventually resume_writing() is called once when the
44*cda5da8dSAndroid Build Coastguard Worker        buffer size reaches the low-water mark.
45*cda5da8dSAndroid Build Coastguard Worker
46*cda5da8dSAndroid Build Coastguard Worker        Note that if the buffer size equals the high-water mark,
47*cda5da8dSAndroid Build Coastguard Worker        pause_writing() is not called -- it must go strictly over.
48*cda5da8dSAndroid Build Coastguard Worker        Conversely, resume_writing() is called when the buffer size is
49*cda5da8dSAndroid Build Coastguard Worker        equal or lower than the low-water mark.  These end conditions
50*cda5da8dSAndroid Build Coastguard Worker        are important to ensure that things go as expected when either
51*cda5da8dSAndroid Build Coastguard Worker        mark is zero.
52*cda5da8dSAndroid Build Coastguard Worker
53*cda5da8dSAndroid Build Coastguard Worker        NOTE: This is the only Protocol callback that is not called
54*cda5da8dSAndroid Build Coastguard Worker        through EventLoop.call_soon() -- if it were, it would have no
55*cda5da8dSAndroid Build Coastguard Worker        effect when it's most needed (when the app keeps writing
56*cda5da8dSAndroid Build Coastguard Worker        without yielding until pause_writing() is called).
57*cda5da8dSAndroid Build Coastguard Worker        """
58*cda5da8dSAndroid Build Coastguard Worker
59*cda5da8dSAndroid Build Coastguard Worker    def resume_writing(self):
60*cda5da8dSAndroid Build Coastguard Worker        """Called when the transport's buffer drains below the low-water mark.
61*cda5da8dSAndroid Build Coastguard Worker
62*cda5da8dSAndroid Build Coastguard Worker        See pause_writing() for details.
63*cda5da8dSAndroid Build Coastguard Worker        """
64*cda5da8dSAndroid Build Coastguard Worker
65*cda5da8dSAndroid Build Coastguard Worker
66*cda5da8dSAndroid Build Coastguard Workerclass Protocol(BaseProtocol):
67*cda5da8dSAndroid Build Coastguard Worker    """Interface for stream protocol.
68*cda5da8dSAndroid Build Coastguard Worker
69*cda5da8dSAndroid Build Coastguard Worker    The user should implement this interface.  They can inherit from
70*cda5da8dSAndroid Build Coastguard Worker    this class but don't need to.  The implementations here do
71*cda5da8dSAndroid Build Coastguard Worker    nothing (they don't raise exceptions).
72*cda5da8dSAndroid Build Coastguard Worker
73*cda5da8dSAndroid Build Coastguard Worker    When the user wants to requests a transport, they pass a protocol
74*cda5da8dSAndroid Build Coastguard Worker    factory to a utility function (e.g., EventLoop.create_connection()).
75*cda5da8dSAndroid Build Coastguard Worker
76*cda5da8dSAndroid Build Coastguard Worker    When the connection is made successfully, connection_made() is
77*cda5da8dSAndroid Build Coastguard Worker    called with a suitable transport object.  Then data_received()
78*cda5da8dSAndroid Build Coastguard Worker    will be called 0 or more times with data (bytes) received from the
79*cda5da8dSAndroid Build Coastguard Worker    transport; finally, connection_lost() will be called exactly once
80*cda5da8dSAndroid Build Coastguard Worker    with either an exception object or None as an argument.
81*cda5da8dSAndroid Build Coastguard Worker
82*cda5da8dSAndroid Build Coastguard Worker    State machine of calls:
83*cda5da8dSAndroid Build Coastguard Worker
84*cda5da8dSAndroid Build Coastguard Worker      start -> CM [-> DR*] [-> ER?] -> CL -> end
85*cda5da8dSAndroid Build Coastguard Worker
86*cda5da8dSAndroid Build Coastguard Worker    * CM: connection_made()
87*cda5da8dSAndroid Build Coastguard Worker    * DR: data_received()
88*cda5da8dSAndroid Build Coastguard Worker    * ER: eof_received()
89*cda5da8dSAndroid Build Coastguard Worker    * CL: connection_lost()
90*cda5da8dSAndroid Build Coastguard Worker    """
91*cda5da8dSAndroid Build Coastguard Worker
92*cda5da8dSAndroid Build Coastguard Worker    __slots__ = ()
93*cda5da8dSAndroid Build Coastguard Worker
94*cda5da8dSAndroid Build Coastguard Worker    def data_received(self, data):
95*cda5da8dSAndroid Build Coastguard Worker        """Called when some data is received.
96*cda5da8dSAndroid Build Coastguard Worker
97*cda5da8dSAndroid Build Coastguard Worker        The argument is a bytes object.
98*cda5da8dSAndroid Build Coastguard Worker        """
99*cda5da8dSAndroid Build Coastguard Worker
100*cda5da8dSAndroid Build Coastguard Worker    def eof_received(self):
101*cda5da8dSAndroid Build Coastguard Worker        """Called when the other end calls write_eof() or equivalent.
102*cda5da8dSAndroid Build Coastguard Worker
103*cda5da8dSAndroid Build Coastguard Worker        If this returns a false value (including None), the transport
104*cda5da8dSAndroid Build Coastguard Worker        will close itself.  If it returns a true value, closing the
105*cda5da8dSAndroid Build Coastguard Worker        transport is up to the protocol.
106*cda5da8dSAndroid Build Coastguard Worker        """
107*cda5da8dSAndroid Build Coastguard Worker
108*cda5da8dSAndroid Build Coastguard Worker
109*cda5da8dSAndroid Build Coastguard Workerclass BufferedProtocol(BaseProtocol):
110*cda5da8dSAndroid Build Coastguard Worker    """Interface for stream protocol with manual buffer control.
111*cda5da8dSAndroid Build Coastguard Worker
112*cda5da8dSAndroid Build Coastguard Worker    Event methods, such as `create_server` and `create_connection`,
113*cda5da8dSAndroid Build Coastguard Worker    accept factories that return protocols that implement this interface.
114*cda5da8dSAndroid Build Coastguard Worker
115*cda5da8dSAndroid Build Coastguard Worker    The idea of BufferedProtocol is that it allows to manually allocate
116*cda5da8dSAndroid Build Coastguard Worker    and control the receive buffer.  Event loops can then use the buffer
117*cda5da8dSAndroid Build Coastguard Worker    provided by the protocol to avoid unnecessary data copies.  This
118*cda5da8dSAndroid Build Coastguard Worker    can result in noticeable performance improvement for protocols that
119*cda5da8dSAndroid Build Coastguard Worker    receive big amounts of data.  Sophisticated protocols can allocate
120*cda5da8dSAndroid Build Coastguard Worker    the buffer only once at creation time.
121*cda5da8dSAndroid Build Coastguard Worker
122*cda5da8dSAndroid Build Coastguard Worker    State machine of calls:
123*cda5da8dSAndroid Build Coastguard Worker
124*cda5da8dSAndroid Build Coastguard Worker      start -> CM [-> GB [-> BU?]]* [-> ER?] -> CL -> end
125*cda5da8dSAndroid Build Coastguard Worker
126*cda5da8dSAndroid Build Coastguard Worker    * CM: connection_made()
127*cda5da8dSAndroid Build Coastguard Worker    * GB: get_buffer()
128*cda5da8dSAndroid Build Coastguard Worker    * BU: buffer_updated()
129*cda5da8dSAndroid Build Coastguard Worker    * ER: eof_received()
130*cda5da8dSAndroid Build Coastguard Worker    * CL: connection_lost()
131*cda5da8dSAndroid Build Coastguard Worker    """
132*cda5da8dSAndroid Build Coastguard Worker
133*cda5da8dSAndroid Build Coastguard Worker    __slots__ = ()
134*cda5da8dSAndroid Build Coastguard Worker
135*cda5da8dSAndroid Build Coastguard Worker    def get_buffer(self, sizehint):
136*cda5da8dSAndroid Build Coastguard Worker        """Called to allocate a new receive buffer.
137*cda5da8dSAndroid Build Coastguard Worker
138*cda5da8dSAndroid Build Coastguard Worker        *sizehint* is a recommended minimal size for the returned
139*cda5da8dSAndroid Build Coastguard Worker        buffer.  When set to -1, the buffer size can be arbitrary.
140*cda5da8dSAndroid Build Coastguard Worker
141*cda5da8dSAndroid Build Coastguard Worker        Must return an object that implements the
142*cda5da8dSAndroid Build Coastguard Worker        :ref:`buffer protocol <bufferobjects>`.
143*cda5da8dSAndroid Build Coastguard Worker        It is an error to return a zero-sized buffer.
144*cda5da8dSAndroid Build Coastguard Worker        """
145*cda5da8dSAndroid Build Coastguard Worker
146*cda5da8dSAndroid Build Coastguard Worker    def buffer_updated(self, nbytes):
147*cda5da8dSAndroid Build Coastguard Worker        """Called when the buffer was updated with the received data.
148*cda5da8dSAndroid Build Coastguard Worker
149*cda5da8dSAndroid Build Coastguard Worker        *nbytes* is the total number of bytes that were written to
150*cda5da8dSAndroid Build Coastguard Worker        the buffer.
151*cda5da8dSAndroid Build Coastguard Worker        """
152*cda5da8dSAndroid Build Coastguard Worker
153*cda5da8dSAndroid Build Coastguard Worker    def eof_received(self):
154*cda5da8dSAndroid Build Coastguard Worker        """Called when the other end calls write_eof() or equivalent.
155*cda5da8dSAndroid Build Coastguard Worker
156*cda5da8dSAndroid Build Coastguard Worker        If this returns a false value (including None), the transport
157*cda5da8dSAndroid Build Coastguard Worker        will close itself.  If it returns a true value, closing the
158*cda5da8dSAndroid Build Coastguard Worker        transport is up to the protocol.
159*cda5da8dSAndroid Build Coastguard Worker        """
160*cda5da8dSAndroid Build Coastguard Worker
161*cda5da8dSAndroid Build Coastguard Worker
162*cda5da8dSAndroid Build Coastguard Workerclass DatagramProtocol(BaseProtocol):
163*cda5da8dSAndroid Build Coastguard Worker    """Interface for datagram protocol."""
164*cda5da8dSAndroid Build Coastguard Worker
165*cda5da8dSAndroid Build Coastguard Worker    __slots__ = ()
166*cda5da8dSAndroid Build Coastguard Worker
167*cda5da8dSAndroid Build Coastguard Worker    def datagram_received(self, data, addr):
168*cda5da8dSAndroid Build Coastguard Worker        """Called when some datagram is received."""
169*cda5da8dSAndroid Build Coastguard Worker
170*cda5da8dSAndroid Build Coastguard Worker    def error_received(self, exc):
171*cda5da8dSAndroid Build Coastguard Worker        """Called when a send or receive operation raises an OSError.
172*cda5da8dSAndroid Build Coastguard Worker
173*cda5da8dSAndroid Build Coastguard Worker        (Other than BlockingIOError or InterruptedError.)
174*cda5da8dSAndroid Build Coastguard Worker        """
175*cda5da8dSAndroid Build Coastguard Worker
176*cda5da8dSAndroid Build Coastguard Worker
177*cda5da8dSAndroid Build Coastguard Workerclass SubprocessProtocol(BaseProtocol):
178*cda5da8dSAndroid Build Coastguard Worker    """Interface for protocol for subprocess calls."""
179*cda5da8dSAndroid Build Coastguard Worker
180*cda5da8dSAndroid Build Coastguard Worker    __slots__ = ()
181*cda5da8dSAndroid Build Coastguard Worker
182*cda5da8dSAndroid Build Coastguard Worker    def pipe_data_received(self, fd, data):
183*cda5da8dSAndroid Build Coastguard Worker        """Called when the subprocess writes data into stdout/stderr pipe.
184*cda5da8dSAndroid Build Coastguard Worker
185*cda5da8dSAndroid Build Coastguard Worker        fd is int file descriptor.
186*cda5da8dSAndroid Build Coastguard Worker        data is bytes object.
187*cda5da8dSAndroid Build Coastguard Worker        """
188*cda5da8dSAndroid Build Coastguard Worker
189*cda5da8dSAndroid Build Coastguard Worker    def pipe_connection_lost(self, fd, exc):
190*cda5da8dSAndroid Build Coastguard Worker        """Called when a file descriptor associated with the child process is
191*cda5da8dSAndroid Build Coastguard Worker        closed.
192*cda5da8dSAndroid Build Coastguard Worker
193*cda5da8dSAndroid Build Coastguard Worker        fd is the int file descriptor that was closed.
194*cda5da8dSAndroid Build Coastguard Worker        """
195*cda5da8dSAndroid Build Coastguard Worker
196*cda5da8dSAndroid Build Coastguard Worker    def process_exited(self):
197*cda5da8dSAndroid Build Coastguard Worker        """Called when subprocess has exited."""
198*cda5da8dSAndroid Build Coastguard Worker
199*cda5da8dSAndroid Build Coastguard Worker
200*cda5da8dSAndroid Build Coastguard Workerdef _feed_data_to_buffered_proto(proto, data):
201*cda5da8dSAndroid Build Coastguard Worker    data_len = len(data)
202*cda5da8dSAndroid Build Coastguard Worker    while data_len:
203*cda5da8dSAndroid Build Coastguard Worker        buf = proto.get_buffer(data_len)
204*cda5da8dSAndroid Build Coastguard Worker        buf_len = len(buf)
205*cda5da8dSAndroid Build Coastguard Worker        if not buf_len:
206*cda5da8dSAndroid Build Coastguard Worker            raise RuntimeError('get_buffer() returned an empty buffer')
207*cda5da8dSAndroid Build Coastguard Worker
208*cda5da8dSAndroid Build Coastguard Worker        if buf_len >= data_len:
209*cda5da8dSAndroid Build Coastguard Worker            buf[:data_len] = data
210*cda5da8dSAndroid Build Coastguard Worker            proto.buffer_updated(data_len)
211*cda5da8dSAndroid Build Coastguard Worker            return
212*cda5da8dSAndroid Build Coastguard Worker        else:
213*cda5da8dSAndroid Build Coastguard Worker            buf[:buf_len] = data[:buf_len]
214*cda5da8dSAndroid Build Coastguard Worker            proto.buffer_updated(buf_len)
215*cda5da8dSAndroid Build Coastguard Worker            data = data[buf_len:]
216*cda5da8dSAndroid Build Coastguard Worker            data_len = len(data)
217