1# Portions of this file are derived from CPython's asyncio sources
2# (notably asyncio/streams.py).
3# Copyright (c) Python Software Foundation.
4# Licensed under the Python Software Foundation License Version 2.
5# See LICENSES/PSF-2.0.txt and THIRD_PARTY_NOTICES for details.
6
7import socket
8from asyncio.streams import StreamReader, StreamWriter, StreamReaderProtocol
9from .api_create_server import create_server
10from .api_create_unix_server import create_unix_server
11from .api_create_connection import create_connection
12from .api_create_unix_connection import create_unix_connection
13
14_DEFAULT_LIMIT = 2 ** 16 # 64 KiB
15
16
17async def open_connection(loop, host=None, port=None, *,
18 limit=_DEFAULT_LIMIT, **kwds):
19 """A wrapper for create_connection() returning a (reader, writer) pair.
20
21 The reader returned is a StreamReader instance; the writer is a
22 StreamWriter instance.
23
24 The arguments are all the usual arguments to create_connection()
25 except protocol_factory; most common are positional host and port,
26 with various optional keyword arguments following.
27
28 Additional optional keyword arguments is limit (to set the buffer limit
29 passed to the StreamReader).
30 """
31 kwds.pop("loop", None)
32 reader = StreamReader(limit=limit, loop=loop)
33 protocol = StreamReaderProtocol(reader, loop=loop)
34 transport, _ = await create_connection(
35 loop, lambda: protocol, host, port, **kwds)
36 writer = StreamWriter(transport, protocol, reader, loop)
37 return reader, writer
38
39
40async def start_server(loop, client_connected_cb, host=None, port=None, *,
41 limit=_DEFAULT_LIMIT, **kwds):
42 """Start a socket server, call back for each client connected.
43
44 The first parameter, `client_connected_cb`, takes two parameters:
45 client_reader, client_writer. client_reader is a StreamReader
46 object, while client_writer is a StreamWriter object. This
47 parameter can either be a plain callback function or a coroutine;
48 if it is a coroutine, it will be automatically converted into a
49 Task.
50
51 The rest of the arguments are all the usual arguments to
52 loop.create_server() except protocol_factory; most common are
53 positional host and port, with various optional keyword arguments
54 following. The return value is the same as loop.create_server().
55
56 Additional optional keyword argument is limit (to set the buffer
57 limit passed to the StreamReader).
58
59 The return value is the same as loop.create_server(), i.e. a
60 Server object which can be used to stop the service.
61 """
62 def factory():
63 reader = StreamReader(limit=limit, loop=loop)
64 protocol = StreamReaderProtocol(reader, client_connected_cb,
65 loop=loop)
66 return protocol
67
68 return await create_server(loop, factory, host, port, **kwds)
69
70
71if hasattr(socket, 'AF_UNIX'):
72 # UNIX Domain Sockets are supported on this platform
73
74 async def open_unix_connection(loop, path=None, *,
75 limit=_DEFAULT_LIMIT, **kwds):
76 """Similar to `open_connection` but works with UNIX Domain Sockets."""
77 reader = StreamReader(limit=limit, loop=loop)
78 protocol = StreamReaderProtocol(reader, loop=loop)
79 transport, _ = await create_unix_connection(
80 loop, lambda: protocol, path, **kwds)
81 writer = StreamWriter(transport, protocol, reader, loop)
82 return reader, writer
83
84 async def start_unix_server(loop, client_connected_cb, path=None, *,
85 limit=_DEFAULT_LIMIT, **kwds):
86 """Similar to `start_server` but works with UNIX Domain Sockets."""
87 def factory():
88 reader = StreamReader(limit=limit, loop=loop)
89 protocol = StreamReaderProtocol(reader, client_connected_cb,
90 loop=loop)
91 return protocol
92
93 return await create_unix_server(loop, factory, path, **kwds)