99 lines
2.9 KiB
Python
99 lines
2.9 KiB
Python
|
"""Abstract Protocol class."""
|
||
|
|
||
|
__all__ = ['Protocol', 'DatagramProtocol']
|
||
|
|
||
|
|
||
|
class BaseProtocol:
|
||
|
"""ABC for base protocol class.
|
||
|
|
||
|
Usually user implements protocols that derived from BaseProtocol
|
||
|
like Protocol or ProcessProtocol.
|
||
|
|
||
|
The only case when BaseProtocol should be implemented directly is
|
||
|
write-only transport like write pipe
|
||
|
"""
|
||
|
|
||
|
def connection_made(self, transport):
|
||
|
"""Called when a connection is made.
|
||
|
|
||
|
The argument is the transport representing the pipe connection.
|
||
|
To receive data, wait for data_received() calls.
|
||
|
When the connection is closed, connection_lost() is called.
|
||
|
"""
|
||
|
|
||
|
def connection_lost(self, exc):
|
||
|
"""Called when the connection is lost or closed.
|
||
|
|
||
|
The argument is an exception object or None (the latter
|
||
|
meaning a regular EOF is received or the connection was
|
||
|
aborted or closed).
|
||
|
"""
|
||
|
|
||
|
|
||
|
class Protocol(BaseProtocol):
|
||
|
"""ABC representing a protocol.
|
||
|
|
||
|
The user should implement this interface. They can inherit from
|
||
|
this class but don't need to. The implementations here do
|
||
|
nothing (they don't raise exceptions).
|
||
|
|
||
|
When the user wants to requests a transport, they pass a protocol
|
||
|
factory to a utility function (e.g., EventLoop.create_connection()).
|
||
|
|
||
|
When the connection is made successfully, connection_made() is
|
||
|
called with a suitable transport object. Then data_received()
|
||
|
will be called 0 or more times with data (bytes) received from the
|
||
|
transport; finally, connection_lost() will be called exactly once
|
||
|
with either an exception object or None as an argument.
|
||
|
|
||
|
State machine of calls:
|
||
|
|
||
|
start -> CM [-> DR*] [-> ER?] -> CL -> end
|
||
|
"""
|
||
|
|
||
|
def data_received(self, data):
|
||
|
"""Called when some data is received.
|
||
|
|
||
|
The argument is a bytes object.
|
||
|
"""
|
||
|
|
||
|
def eof_received(self):
|
||
|
"""Called when the other end calls write_eof() or equivalent.
|
||
|
|
||
|
If this returns a false value (including None), the transport
|
||
|
will close itself. If it returns a true value, closing the
|
||
|
transport is up to the protocol.
|
||
|
"""
|
||
|
|
||
|
|
||
|
class DatagramProtocol(BaseProtocol):
|
||
|
"""ABC representing a datagram protocol."""
|
||
|
|
||
|
def datagram_received(self, data, addr):
|
||
|
"""Called when some datagram is received."""
|
||
|
|
||
|
def connection_refused(self, exc):
|
||
|
"""Connection is refused."""
|
||
|
|
||
|
|
||
|
class SubprocessProtocol(BaseProtocol):
|
||
|
"""ABC representing a protocol for subprocess calls."""
|
||
|
|
||
|
def pipe_data_received(self, fd, data):
|
||
|
"""Called when subprocess write a data into stdout/stderr pipes.
|
||
|
|
||
|
fd is int file dascriptor.
|
||
|
data is bytes object.
|
||
|
"""
|
||
|
|
||
|
def pipe_connection_lost(self, fd, exc):
|
||
|
"""Called when a file descriptor associated with the child process is
|
||
|
closed.
|
||
|
|
||
|
fd is the int file descriptor that was closed.
|
||
|
"""
|
||
|
|
||
|
def process_exited(self):
|
||
|
"""Called when subprocess has exited.
|
||
|
"""
|