17db96d56Sopenharmony_ci"""Abstract Transport class."""
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ci__all__ = (
47db96d56Sopenharmony_ci    'BaseTransport', 'ReadTransport', 'WriteTransport',
57db96d56Sopenharmony_ci    'Transport', 'DatagramTransport', 'SubprocessTransport',
67db96d56Sopenharmony_ci)
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ciclass BaseTransport:
107db96d56Sopenharmony_ci    """Base class for transports."""
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ci    __slots__ = ('_extra',)
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ci    def __init__(self, extra=None):
157db96d56Sopenharmony_ci        if extra is None:
167db96d56Sopenharmony_ci            extra = {}
177db96d56Sopenharmony_ci        self._extra = extra
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_ci    def get_extra_info(self, name, default=None):
207db96d56Sopenharmony_ci        """Get optional transport information."""
217db96d56Sopenharmony_ci        return self._extra.get(name, default)
227db96d56Sopenharmony_ci
237db96d56Sopenharmony_ci    def is_closing(self):
247db96d56Sopenharmony_ci        """Return True if the transport is closing or closed."""
257db96d56Sopenharmony_ci        raise NotImplementedError
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ci    def close(self):
287db96d56Sopenharmony_ci        """Close the transport.
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ci        Buffered data will be flushed asynchronously.  No more data
317db96d56Sopenharmony_ci        will be received.  After all buffered data is flushed, the
327db96d56Sopenharmony_ci        protocol's connection_lost() method will (eventually) be
337db96d56Sopenharmony_ci        called with None as its argument.
347db96d56Sopenharmony_ci        """
357db96d56Sopenharmony_ci        raise NotImplementedError
367db96d56Sopenharmony_ci
377db96d56Sopenharmony_ci    def set_protocol(self, protocol):
387db96d56Sopenharmony_ci        """Set a new protocol."""
397db96d56Sopenharmony_ci        raise NotImplementedError
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ci    def get_protocol(self):
427db96d56Sopenharmony_ci        """Return the current protocol."""
437db96d56Sopenharmony_ci        raise NotImplementedError
447db96d56Sopenharmony_ci
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_ciclass ReadTransport(BaseTransport):
477db96d56Sopenharmony_ci    """Interface for read-only transports."""
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_ci    __slots__ = ()
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_ci    def is_reading(self):
527db96d56Sopenharmony_ci        """Return True if the transport is receiving."""
537db96d56Sopenharmony_ci        raise NotImplementedError
547db96d56Sopenharmony_ci
557db96d56Sopenharmony_ci    def pause_reading(self):
567db96d56Sopenharmony_ci        """Pause the receiving end.
577db96d56Sopenharmony_ci
587db96d56Sopenharmony_ci        No data will be passed to the protocol's data_received()
597db96d56Sopenharmony_ci        method until resume_reading() is called.
607db96d56Sopenharmony_ci        """
617db96d56Sopenharmony_ci        raise NotImplementedError
627db96d56Sopenharmony_ci
637db96d56Sopenharmony_ci    def resume_reading(self):
647db96d56Sopenharmony_ci        """Resume the receiving end.
657db96d56Sopenharmony_ci
667db96d56Sopenharmony_ci        Data received will once again be passed to the protocol's
677db96d56Sopenharmony_ci        data_received() method.
687db96d56Sopenharmony_ci        """
697db96d56Sopenharmony_ci        raise NotImplementedError
707db96d56Sopenharmony_ci
717db96d56Sopenharmony_ci
727db96d56Sopenharmony_ciclass WriteTransport(BaseTransport):
737db96d56Sopenharmony_ci    """Interface for write-only transports."""
747db96d56Sopenharmony_ci
757db96d56Sopenharmony_ci    __slots__ = ()
767db96d56Sopenharmony_ci
777db96d56Sopenharmony_ci    def set_write_buffer_limits(self, high=None, low=None):
787db96d56Sopenharmony_ci        """Set the high- and low-water limits for write flow control.
797db96d56Sopenharmony_ci
807db96d56Sopenharmony_ci        These two values control when to call the protocol's
817db96d56Sopenharmony_ci        pause_writing() and resume_writing() methods.  If specified,
827db96d56Sopenharmony_ci        the low-water limit must be less than or equal to the
837db96d56Sopenharmony_ci        high-water limit.  Neither value can be negative.
847db96d56Sopenharmony_ci
857db96d56Sopenharmony_ci        The defaults are implementation-specific.  If only the
867db96d56Sopenharmony_ci        high-water limit is given, the low-water limit defaults to an
877db96d56Sopenharmony_ci        implementation-specific value less than or equal to the
887db96d56Sopenharmony_ci        high-water limit.  Setting high to zero forces low to zero as
897db96d56Sopenharmony_ci        well, and causes pause_writing() to be called whenever the
907db96d56Sopenharmony_ci        buffer becomes non-empty.  Setting low to zero causes
917db96d56Sopenharmony_ci        resume_writing() to be called only once the buffer is empty.
927db96d56Sopenharmony_ci        Use of zero for either limit is generally sub-optimal as it
937db96d56Sopenharmony_ci        reduces opportunities for doing I/O and computation
947db96d56Sopenharmony_ci        concurrently.
957db96d56Sopenharmony_ci        """
967db96d56Sopenharmony_ci        raise NotImplementedError
977db96d56Sopenharmony_ci
987db96d56Sopenharmony_ci    def get_write_buffer_size(self):
997db96d56Sopenharmony_ci        """Return the current size of the write buffer."""
1007db96d56Sopenharmony_ci        raise NotImplementedError
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ci    def get_write_buffer_limits(self):
1037db96d56Sopenharmony_ci        """Get the high and low watermarks for write flow control.
1047db96d56Sopenharmony_ci        Return a tuple (low, high) where low and high are
1057db96d56Sopenharmony_ci        positive number of bytes."""
1067db96d56Sopenharmony_ci        raise NotImplementedError
1077db96d56Sopenharmony_ci
1087db96d56Sopenharmony_ci    def write(self, data):
1097db96d56Sopenharmony_ci        """Write some data bytes to the transport.
1107db96d56Sopenharmony_ci
1117db96d56Sopenharmony_ci        This does not block; it buffers the data and arranges for it
1127db96d56Sopenharmony_ci        to be sent out asynchronously.
1137db96d56Sopenharmony_ci        """
1147db96d56Sopenharmony_ci        raise NotImplementedError
1157db96d56Sopenharmony_ci
1167db96d56Sopenharmony_ci    def writelines(self, list_of_data):
1177db96d56Sopenharmony_ci        """Write a list (or any iterable) of data bytes to the transport.
1187db96d56Sopenharmony_ci
1197db96d56Sopenharmony_ci        The default implementation concatenates the arguments and
1207db96d56Sopenharmony_ci        calls write() on the result.
1217db96d56Sopenharmony_ci        """
1227db96d56Sopenharmony_ci        data = b''.join(list_of_data)
1237db96d56Sopenharmony_ci        self.write(data)
1247db96d56Sopenharmony_ci
1257db96d56Sopenharmony_ci    def write_eof(self):
1267db96d56Sopenharmony_ci        """Close the write end after flushing buffered data.
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_ci        (This is like typing ^D into a UNIX program reading from stdin.)
1297db96d56Sopenharmony_ci
1307db96d56Sopenharmony_ci        Data may still be received.
1317db96d56Sopenharmony_ci        """
1327db96d56Sopenharmony_ci        raise NotImplementedError
1337db96d56Sopenharmony_ci
1347db96d56Sopenharmony_ci    def can_write_eof(self):
1357db96d56Sopenharmony_ci        """Return True if this transport supports write_eof(), False if not."""
1367db96d56Sopenharmony_ci        raise NotImplementedError
1377db96d56Sopenharmony_ci
1387db96d56Sopenharmony_ci    def abort(self):
1397db96d56Sopenharmony_ci        """Close the transport immediately.
1407db96d56Sopenharmony_ci
1417db96d56Sopenharmony_ci        Buffered data will be lost.  No more data will be received.
1427db96d56Sopenharmony_ci        The protocol's connection_lost() method will (eventually) be
1437db96d56Sopenharmony_ci        called with None as its argument.
1447db96d56Sopenharmony_ci        """
1457db96d56Sopenharmony_ci        raise NotImplementedError
1467db96d56Sopenharmony_ci
1477db96d56Sopenharmony_ci
1487db96d56Sopenharmony_ciclass Transport(ReadTransport, WriteTransport):
1497db96d56Sopenharmony_ci    """Interface representing a bidirectional transport.
1507db96d56Sopenharmony_ci
1517db96d56Sopenharmony_ci    There may be several implementations, but typically, the user does
1527db96d56Sopenharmony_ci    not implement new transports; rather, the platform provides some
1537db96d56Sopenharmony_ci    useful transports that are implemented using the platform's best
1547db96d56Sopenharmony_ci    practices.
1557db96d56Sopenharmony_ci
1567db96d56Sopenharmony_ci    The user never instantiates a transport directly; they call a
1577db96d56Sopenharmony_ci    utility function, passing it a protocol factory and other
1587db96d56Sopenharmony_ci    information necessary to create the transport and protocol.  (E.g.
1597db96d56Sopenharmony_ci    EventLoop.create_connection() or EventLoop.create_server().)
1607db96d56Sopenharmony_ci
1617db96d56Sopenharmony_ci    The utility function will asynchronously create a transport and a
1627db96d56Sopenharmony_ci    protocol and hook them up by calling the protocol's
1637db96d56Sopenharmony_ci    connection_made() method, passing it the transport.
1647db96d56Sopenharmony_ci
1657db96d56Sopenharmony_ci    The implementation here raises NotImplemented for every method
1667db96d56Sopenharmony_ci    except writelines(), which calls write() in a loop.
1677db96d56Sopenharmony_ci    """
1687db96d56Sopenharmony_ci
1697db96d56Sopenharmony_ci    __slots__ = ()
1707db96d56Sopenharmony_ci
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_ciclass DatagramTransport(BaseTransport):
1737db96d56Sopenharmony_ci    """Interface for datagram (UDP) transports."""
1747db96d56Sopenharmony_ci
1757db96d56Sopenharmony_ci    __slots__ = ()
1767db96d56Sopenharmony_ci
1777db96d56Sopenharmony_ci    def sendto(self, data, addr=None):
1787db96d56Sopenharmony_ci        """Send data to the transport.
1797db96d56Sopenharmony_ci
1807db96d56Sopenharmony_ci        This does not block; it buffers the data and arranges for it
1817db96d56Sopenharmony_ci        to be sent out asynchronously.
1827db96d56Sopenharmony_ci        addr is target socket address.
1837db96d56Sopenharmony_ci        If addr is None use target address pointed on transport creation.
1847db96d56Sopenharmony_ci        """
1857db96d56Sopenharmony_ci        raise NotImplementedError
1867db96d56Sopenharmony_ci
1877db96d56Sopenharmony_ci    def abort(self):
1887db96d56Sopenharmony_ci        """Close the transport immediately.
1897db96d56Sopenharmony_ci
1907db96d56Sopenharmony_ci        Buffered data will be lost.  No more data will be received.
1917db96d56Sopenharmony_ci        The protocol's connection_lost() method will (eventually) be
1927db96d56Sopenharmony_ci        called with None as its argument.
1937db96d56Sopenharmony_ci        """
1947db96d56Sopenharmony_ci        raise NotImplementedError
1957db96d56Sopenharmony_ci
1967db96d56Sopenharmony_ci
1977db96d56Sopenharmony_ciclass SubprocessTransport(BaseTransport):
1987db96d56Sopenharmony_ci
1997db96d56Sopenharmony_ci    __slots__ = ()
2007db96d56Sopenharmony_ci
2017db96d56Sopenharmony_ci    def get_pid(self):
2027db96d56Sopenharmony_ci        """Get subprocess id."""
2037db96d56Sopenharmony_ci        raise NotImplementedError
2047db96d56Sopenharmony_ci
2057db96d56Sopenharmony_ci    def get_returncode(self):
2067db96d56Sopenharmony_ci        """Get subprocess returncode.
2077db96d56Sopenharmony_ci
2087db96d56Sopenharmony_ci        See also
2097db96d56Sopenharmony_ci        http://docs.python.org/3/library/subprocess#subprocess.Popen.returncode
2107db96d56Sopenharmony_ci        """
2117db96d56Sopenharmony_ci        raise NotImplementedError
2127db96d56Sopenharmony_ci
2137db96d56Sopenharmony_ci    def get_pipe_transport(self, fd):
2147db96d56Sopenharmony_ci        """Get transport for pipe with number fd."""
2157db96d56Sopenharmony_ci        raise NotImplementedError
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_ci    def send_signal(self, signal):
2187db96d56Sopenharmony_ci        """Send signal to subprocess.
2197db96d56Sopenharmony_ci
2207db96d56Sopenharmony_ci        See also:
2217db96d56Sopenharmony_ci        docs.python.org/3/library/subprocess#subprocess.Popen.send_signal
2227db96d56Sopenharmony_ci        """
2237db96d56Sopenharmony_ci        raise NotImplementedError
2247db96d56Sopenharmony_ci
2257db96d56Sopenharmony_ci    def terminate(self):
2267db96d56Sopenharmony_ci        """Stop the subprocess.
2277db96d56Sopenharmony_ci
2287db96d56Sopenharmony_ci        Alias for close() method.
2297db96d56Sopenharmony_ci
2307db96d56Sopenharmony_ci        On Posix OSs the method sends SIGTERM to the subprocess.
2317db96d56Sopenharmony_ci        On Windows the Win32 API function TerminateProcess()
2327db96d56Sopenharmony_ci         is called to stop the subprocess.
2337db96d56Sopenharmony_ci
2347db96d56Sopenharmony_ci        See also:
2357db96d56Sopenharmony_ci        http://docs.python.org/3/library/subprocess#subprocess.Popen.terminate
2367db96d56Sopenharmony_ci        """
2377db96d56Sopenharmony_ci        raise NotImplementedError
2387db96d56Sopenharmony_ci
2397db96d56Sopenharmony_ci    def kill(self):
2407db96d56Sopenharmony_ci        """Kill the subprocess.
2417db96d56Sopenharmony_ci
2427db96d56Sopenharmony_ci        On Posix OSs the function sends SIGKILL to the subprocess.
2437db96d56Sopenharmony_ci        On Windows kill() is an alias for terminate().
2447db96d56Sopenharmony_ci
2457db96d56Sopenharmony_ci        See also:
2467db96d56Sopenharmony_ci        http://docs.python.org/3/library/subprocess#subprocess.Popen.kill
2477db96d56Sopenharmony_ci        """
2487db96d56Sopenharmony_ci        raise NotImplementedError
2497db96d56Sopenharmony_ci
2507db96d56Sopenharmony_ci
2517db96d56Sopenharmony_ciclass _FlowControlMixin(Transport):
2527db96d56Sopenharmony_ci    """All the logic for (write) flow control in a mix-in base class.
2537db96d56Sopenharmony_ci
2547db96d56Sopenharmony_ci    The subclass must implement get_write_buffer_size().  It must call
2557db96d56Sopenharmony_ci    _maybe_pause_protocol() whenever the write buffer size increases,
2567db96d56Sopenharmony_ci    and _maybe_resume_protocol() whenever it decreases.  It may also
2577db96d56Sopenharmony_ci    override set_write_buffer_limits() (e.g. to specify different
2587db96d56Sopenharmony_ci    defaults).
2597db96d56Sopenharmony_ci
2607db96d56Sopenharmony_ci    The subclass constructor must call super().__init__(extra).  This
2617db96d56Sopenharmony_ci    will call set_write_buffer_limits().
2627db96d56Sopenharmony_ci
2637db96d56Sopenharmony_ci    The user may call set_write_buffer_limits() and
2647db96d56Sopenharmony_ci    get_write_buffer_size(), and their protocol's pause_writing() and
2657db96d56Sopenharmony_ci    resume_writing() may be called.
2667db96d56Sopenharmony_ci    """
2677db96d56Sopenharmony_ci
2687db96d56Sopenharmony_ci    __slots__ = ('_loop', '_protocol_paused', '_high_water', '_low_water')
2697db96d56Sopenharmony_ci
2707db96d56Sopenharmony_ci    def __init__(self, extra=None, loop=None):
2717db96d56Sopenharmony_ci        super().__init__(extra)
2727db96d56Sopenharmony_ci        assert loop is not None
2737db96d56Sopenharmony_ci        self._loop = loop
2747db96d56Sopenharmony_ci        self._protocol_paused = False
2757db96d56Sopenharmony_ci        self._set_write_buffer_limits()
2767db96d56Sopenharmony_ci
2777db96d56Sopenharmony_ci    def _maybe_pause_protocol(self):
2787db96d56Sopenharmony_ci        size = self.get_write_buffer_size()
2797db96d56Sopenharmony_ci        if size <= self._high_water:
2807db96d56Sopenharmony_ci            return
2817db96d56Sopenharmony_ci        if not self._protocol_paused:
2827db96d56Sopenharmony_ci            self._protocol_paused = True
2837db96d56Sopenharmony_ci            try:
2847db96d56Sopenharmony_ci                self._protocol.pause_writing()
2857db96d56Sopenharmony_ci            except (SystemExit, KeyboardInterrupt):
2867db96d56Sopenharmony_ci                raise
2877db96d56Sopenharmony_ci            except BaseException as exc:
2887db96d56Sopenharmony_ci                self._loop.call_exception_handler({
2897db96d56Sopenharmony_ci                    'message': 'protocol.pause_writing() failed',
2907db96d56Sopenharmony_ci                    'exception': exc,
2917db96d56Sopenharmony_ci                    'transport': self,
2927db96d56Sopenharmony_ci                    'protocol': self._protocol,
2937db96d56Sopenharmony_ci                })
2947db96d56Sopenharmony_ci
2957db96d56Sopenharmony_ci    def _maybe_resume_protocol(self):
2967db96d56Sopenharmony_ci        if (self._protocol_paused and
2977db96d56Sopenharmony_ci                self.get_write_buffer_size() <= self._low_water):
2987db96d56Sopenharmony_ci            self._protocol_paused = False
2997db96d56Sopenharmony_ci            try:
3007db96d56Sopenharmony_ci                self._protocol.resume_writing()
3017db96d56Sopenharmony_ci            except (SystemExit, KeyboardInterrupt):
3027db96d56Sopenharmony_ci                raise
3037db96d56Sopenharmony_ci            except BaseException as exc:
3047db96d56Sopenharmony_ci                self._loop.call_exception_handler({
3057db96d56Sopenharmony_ci                    'message': 'protocol.resume_writing() failed',
3067db96d56Sopenharmony_ci                    'exception': exc,
3077db96d56Sopenharmony_ci                    'transport': self,
3087db96d56Sopenharmony_ci                    'protocol': self._protocol,
3097db96d56Sopenharmony_ci                })
3107db96d56Sopenharmony_ci
3117db96d56Sopenharmony_ci    def get_write_buffer_limits(self):
3127db96d56Sopenharmony_ci        return (self._low_water, self._high_water)
3137db96d56Sopenharmony_ci
3147db96d56Sopenharmony_ci    def _set_write_buffer_limits(self, high=None, low=None):
3157db96d56Sopenharmony_ci        if high is None:
3167db96d56Sopenharmony_ci            if low is None:
3177db96d56Sopenharmony_ci                high = 64 * 1024
3187db96d56Sopenharmony_ci            else:
3197db96d56Sopenharmony_ci                high = 4 * low
3207db96d56Sopenharmony_ci        if low is None:
3217db96d56Sopenharmony_ci            low = high // 4
3227db96d56Sopenharmony_ci
3237db96d56Sopenharmony_ci        if not high >= low >= 0:
3247db96d56Sopenharmony_ci            raise ValueError(
3257db96d56Sopenharmony_ci                f'high ({high!r}) must be >= low ({low!r}) must be >= 0')
3267db96d56Sopenharmony_ci
3277db96d56Sopenharmony_ci        self._high_water = high
3287db96d56Sopenharmony_ci        self._low_water = low
3297db96d56Sopenharmony_ci
3307db96d56Sopenharmony_ci    def set_write_buffer_limits(self, high=None, low=None):
3317db96d56Sopenharmony_ci        self._set_write_buffer_limits(high=high, low=low)
3327db96d56Sopenharmony_ci        self._maybe_pause_protocol()
3337db96d56Sopenharmony_ci
3347db96d56Sopenharmony_ci    def get_write_buffer_size(self):
3357db96d56Sopenharmony_ci        raise NotImplementedError
336