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