omserv 0.0.0.dev178__py3-none-any.whl → 0.0.0.dev180__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
omserv/server/__init__.py CHANGED
@@ -15,4 +15,4 @@ See:
15
15
  - https://github.com/tiangolo/fastapi
16
16
  """
17
17
  from .config import Config # noqa
18
- from .workers import serve # noqa
18
+ from .default import serve # noqa
@@ -0,0 +1,34 @@
1
+ import typing as ta
2
+
3
+ import anyio.abc
4
+
5
+ from omlish import inject as inj
6
+
7
+ from .config import Config
8
+ from .inject import bind_server
9
+ from .listener import Listener
10
+ from .sockets import Sockets
11
+ from .types import AppWrapper
12
+ from .types import AsgiFramework
13
+ from .types import wrap_app
14
+
15
+
16
+ async def serve(
17
+ app: AsgiFramework | AppWrapper,
18
+ config: Config,
19
+ *,
20
+ sockets: Sockets | None = None,
21
+ shutdown_trigger: ta.Callable[..., ta.Awaitable[None]] | None = None,
22
+ handle_shutdown_signals: bool = False,
23
+ task_status: anyio.abc.TaskStatus[ta.Sequence[str]] = anyio.TASK_STATUS_IGNORED,
24
+ ) -> None:
25
+ injector = inj.create_injector(bind_server(config))
26
+ listener = injector.inject(Listener)
27
+ await listener.listen(
28
+ wrap_app(app),
29
+ config,
30
+ sockets=sockets,
31
+ shutdown_trigger=shutdown_trigger,
32
+ handle_shutdown_signals=handle_shutdown_signals,
33
+ task_status=task_status,
34
+ )
@@ -0,0 +1,21 @@
1
+ import functools
2
+
3
+ from omlish import inject as inj
4
+
5
+ from .config import Config
6
+ from .server import Server
7
+ from .server import ServerFactory
8
+
9
+
10
+ def _provide_server_factory(config: Config) -> ServerFactory:
11
+ return ServerFactory(functools.partial(Server, config=config))
12
+
13
+
14
+ def bind_server(
15
+ config: Config,
16
+ ) -> inj.Elemental:
17
+ return inj.as_elements(
18
+ inj.bind(config),
19
+
20
+ inj.bind(_provide_server_factory, singleton=True),
21
+ )
@@ -11,10 +11,10 @@ import anyio.abc
11
11
 
12
12
  from .config import Config
13
13
  from .lifespans import Lifespan
14
+ from .server import ServerFactory
14
15
  from .sockets import Sockets
15
16
  from .sockets import create_sockets
16
17
  from .sockets import repr_socket_addr
17
- from .tcpserver import TcpServer
18
18
  from .types import AppWrapper
19
19
  from .types import AsgiFramework
20
20
  from .types import wrap_app
@@ -125,69 +125,80 @@ async def _install_signal_handler(
125
125
  return signal_event.wait
126
126
 
127
127
 
128
- async def serve(
129
- app: AsgiFramework | AppWrapper,
130
- config: Config,
131
- *,
132
- sockets: Sockets | None = None,
133
- shutdown_trigger: ta.Callable[..., ta.Awaitable[None]] | None = None,
134
- handle_shutdown_signals: bool = False,
135
- task_status: anyio.abc.TaskStatus[ta.Sequence[str]] = anyio.TASK_STATUS_IGNORED,
136
- ) -> None:
137
- app = wrap_app(app)
138
-
139
- lifespan = Lifespan(app, config)
140
- max_requests = None
141
- if config.max_requests is not None:
142
- max_requests = config.max_requests + random.randint(0, config.max_requests_jitter)
143
- context = WorkerContext(max_requests)
128
+ class Listener:
129
+ def __init__(
130
+ self,
131
+ *,
132
+ server_factory: ServerFactory,
133
+ ) -> None:
134
+ super().__init__()
135
+
136
+ self._server_factory = server_factory
137
+
138
+ async def listen(
139
+ self,
140
+ app: AsgiFramework | AppWrapper,
141
+ config: Config,
142
+ *,
143
+ sockets: Sockets | None = None,
144
+ shutdown_trigger: ta.Callable[..., ta.Awaitable[None]] | None = None,
145
+ handle_shutdown_signals: bool = False,
146
+ task_status: anyio.abc.TaskStatus[ta.Sequence[str]] = anyio.TASK_STATUS_IGNORED,
147
+ ) -> None:
148
+ app = wrap_app(app)
149
+
150
+ lifespan = Lifespan(app, config)
151
+ max_requests = None
152
+ if config.max_requests is not None:
153
+ max_requests = config.max_requests + random.randint(0, config.max_requests_jitter)
154
+ context = WorkerContext(max_requests)
155
+
156
+ async with anyio.create_task_group() as lifespan_task_group:
157
+ if shutdown_trigger is None and handle_shutdown_signals:
158
+ shutdown_trigger = await _install_signal_handler(lifespan_task_group)
159
+
160
+ await lifespan_task_group.start(lifespan.handle_lifespan)
161
+ await lifespan.wait_for_startup()
162
+
163
+ async with anyio.create_task_group() as server_task_group:
164
+ if sockets is None:
165
+ sockets = create_sockets(config)
166
+ for sock in sockets.insecure_sockets:
167
+ sock.listen(config.backlog)
168
+
169
+ listeners = []
170
+ binds = []
144
171
 
145
- async with anyio.create_task_group() as lifespan_task_group:
146
- if shutdown_trigger is None and handle_shutdown_signals:
147
- shutdown_trigger = await _install_signal_handler(lifespan_task_group)
148
-
149
- await lifespan_task_group.start(lifespan.handle_lifespan)
150
- await lifespan.wait_for_startup()
151
-
152
- async with anyio.create_task_group() as server_task_group:
153
- if sockets is None:
154
- sockets = create_sockets(config)
155
172
  for sock in sockets.insecure_sockets:
156
- sock.listen(config.backlog)
157
-
158
- listeners = []
159
- binds = []
160
-
161
- for sock in sockets.insecure_sockets:
162
- listeners.append(anyio._core._eventloop.get_async_backend().create_tcp_listener(sock)) # noqa
163
- bind = repr_socket_addr(sock.family, sock.getsockname())
164
- binds.append(f'http://{bind}')
165
- log.info('Running on http://%s (CTRL + C to quit)', bind)
166
-
167
- task_status.started(binds)
168
- try:
169
- async with anyio.create_task_group() as task_group:
170
- if shutdown_trigger is not None:
171
- task_group.start_soon(raise_shutdown, shutdown_trigger)
172
- task_group.start_soon(raise_shutdown, context.terminate.wait)
173
-
174
- task_group.start_soon(
175
- functools.partial(
176
- serve_listeners,
177
- functools.partial(TcpServer, app, config, context),
178
- listeners,
179
- handler_task_group=server_task_group,
180
- ),
181
- )
182
-
183
- await anyio.sleep_forever()
184
- except BaseExceptionGroup as error:
185
- _, other_errors = error.split((ShutdownError, KeyboardInterrupt)) # noqa
186
- if other_errors is not None:
187
- raise other_errors # noqa
188
- finally:
189
- await context.terminated.set()
190
- server_task_group.cancel_scope.deadline = anyio.current_time() + config.graceful_timeout
191
-
192
- await lifespan.wait_for_shutdown()
193
- lifespan_task_group.cancel_scope.cancel()
173
+ listeners.append(anyio._core._eventloop.get_async_backend().create_tcp_listener(sock)) # noqa
174
+ bind = repr_socket_addr(sock.family, sock.getsockname())
175
+ binds.append(f'http://{bind}')
176
+ log.info('Running on http://%s (CTRL + C to quit)', bind)
177
+
178
+ task_status.started(binds)
179
+ try:
180
+ async with anyio.create_task_group() as task_group:
181
+ if shutdown_trigger is not None:
182
+ task_group.start_soon(raise_shutdown, shutdown_trigger)
183
+ task_group.start_soon(raise_shutdown, context.terminate.wait)
184
+
185
+ task_group.start_soon(
186
+ functools.partial(
187
+ serve_listeners,
188
+ functools.partial(self._server_factory, app, context),
189
+ listeners,
190
+ handler_task_group=server_task_group,
191
+ ),
192
+ )
193
+
194
+ await anyio.sleep_forever()
195
+ except BaseExceptionGroup as error:
196
+ _, other_errors = error.split((ShutdownError, KeyboardInterrupt)) # noqa
197
+ if other_errors is not None:
198
+ raise other_errors # noqa
199
+ finally:
200
+ await context.terminated.set()
201
+ server_task_group.cancel_scope.deadline = anyio.current_time() + config.graceful_timeout
202
+
203
+ await lifespan.wait_for_shutdown()
204
+ lifespan_task_group.cancel_scope.cancel()
@@ -12,11 +12,11 @@ import typing as ta
12
12
  import anyio
13
13
 
14
14
  from .config import Config
15
+ from .default import serve
15
16
  from .sockets import Sockets
16
17
  from .sockets import create_sockets
17
18
  from .types import AsgiFramework
18
19
  from .types import wrap_app
19
- from .workers import serve
20
20
 
21
21
 
22
22
  async def check_multiprocess_shutdown_event(
@@ -6,6 +6,7 @@ import typing as ta
6
6
  import anyio.abc
7
7
 
8
8
  from omlish import check
9
+ from omlish import lang
9
10
 
10
11
  from .config import Config
11
12
  from .events import Closed
@@ -25,13 +26,18 @@ log = logging.getLogger(__name__)
25
26
  MAX_RECV = 2 ** 16
26
27
 
27
28
 
28
- class TcpServer:
29
+ class ServerFactory(lang.Func3[AppWrapper, WorkerContext, anyio.abc.SocketStream, 'Server']):
30
+ pass
31
+
32
+
33
+ class Server:
29
34
  def __init__(
30
35
  self,
31
36
  app: AppWrapper,
32
- config: Config,
33
37
  context: WorkerContext,
34
38
  stream: anyio.abc.SocketStream,
39
+ *,
40
+ config: Config,
35
41
  ) -> None:
36
42
  super().__init__()
37
43
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omserv
3
- Version: 0.0.0.dev178
3
+ Version: 0.0.0.dev180
4
4
  Summary: omserv
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,7 +12,7 @@ Classifier: Operating System :: OS Independent
12
12
  Classifier: Operating System :: POSIX
13
13
  Requires-Python: >=3.12
14
14
  License-File: LICENSE
15
- Requires-Dist: omlish==0.0.0.dev178
15
+ Requires-Dist: omlish==0.0.0.dev180
16
16
  Provides-Extra: all
17
17
  Requires-Dist: h11~=0.14; extra == "all"
18
18
  Requires-Dist: h2~=4.1; extra == "all"
@@ -21,20 +21,22 @@ omserv/node/models.py,sha256=EOaq-aW1rbGOzHTmTULhbVwV5j_burL07qh2QO9smdM,1273
21
21
  omserv/node/registry.py,sha256=y67VMowll9IuLiTVgauAcbP8-evFJNqpwocwwt7kZL4,3478
22
22
  omserv/node/sql.py,sha256=vy7RP50JiH3jQHMVa7Hxk0pFJK3QcbGeTvyNppB1W4I,2826
23
23
  omserv/server/LICENSE,sha256=VKPNmbyrS9wcwcx20hBlVtLP01brb2dByHrWHeNLPag,1050
24
- omserv/server/__init__.py,sha256=7c9pUvoC-3lByJeGoQfAcp78JCZ9oA5wP0Bzpm87D7Y,372
24
+ omserv/server/__init__.py,sha256=jrFdrxfnQwjK5DW5y9w0alw6IKToGn2IQyZDhsuGHv4,372
25
25
  omserv/server/config.py,sha256=oGWL1kuk45bJ6sVr8n3ow5Q-1nz9EqByjoykU2iOHIY,1189
26
26
  omserv/server/debug.py,sha256=N7RI0Jj-ttmys3DJD0RREmGG5XZpTCp6y9Yu0x98Agg,299
27
+ omserv/server/default.py,sha256=hmfy--Q35QFMU8oTf4uHwVM2qBFG8mQDR9Wik2f1yZk,970
27
28
  omserv/server/events.py,sha256=VMr_rArsVjJYnyH9SqLWtOLUg18vSu1O0ep9gNBGR_c,1369
28
29
  omserv/server/headers.py,sha256=3H-NxMMQg5WuF5wF4AWFUEqkToh4NqNqHouavzbOQok,1188
30
+ omserv/server/inject.py,sha256=mD3MIDd44_nr1mIiDfjzgJ4DCBeD3JILN6STTDNReGc,454
29
31
  omserv/server/lifespans.py,sha256=kRVxDQM18jCBzRUpafyb69q_bGSCyxxjAtrkxjqcZdE,4607
30
- omserv/server/multiprocess.py,sha256=jKmQzj_Nrwxw2mM-Tf3XVf6vPYMbfyCkPOUWVe028Q8,4253
32
+ omserv/server/listener.py,sha256=t_wUlS6pXnRn-aEXV8D8jhWAeIlQ3a3Sx9i_0BOKV70,7033
33
+ omserv/server/multiprocess.py,sha256=qvNFQEMpTXXR5ACdja4JVC0HFgdvb8CL94iKLDYvZ48,4253
34
+ omserv/server/server.py,sha256=hgUTfZAUwF7V-HdsdV98KbYmE1IRKmEO3B1LlKTiPWc,5223
31
35
  omserv/server/sockets.py,sha256=lwqNP7URlp605ibsjHzp0pc-lyjcyTu-hD-uyojLUYk,3389
32
36
  omserv/server/ssl.py,sha256=gmB5ecM8Mck-YtGYF8pb2dwFdjABVGzERFCDzM9lBck,1483
33
37
  omserv/server/taskspawner.py,sha256=ljzF26UPtnp7GLAY_BvjzuwCoCO9aL7TKLwRNTmUy1M,3008
34
- omserv/server/tcpserver.py,sha256=akC-2WOhmoIiJBH0Ti0m1uK_sOTBYGie0CoRkEcUmkA,5082
35
38
  omserv/server/types.py,sha256=XXY5py8RYlEeD4FZrWNqSyX7DD-ffSlcG-T2s9BY9eI,2017
36
39
  omserv/server/workercontext.py,sha256=4rcLuGsyiU7URO7T_eHylOBPPNUS9C23QfEUVyJUtIY,1200
37
- omserv/server/workers.py,sha256=rdV8qEzWKMZ6HnN9nUoGS58U9LRsrsqOcAd_7yl73Y0,6586
38
40
  omserv/server/protocols/__init__.py,sha256=Ryu2PDZ1TUI6F2l-HBEYgyzZ7wHqE6VmjqnS0tIvmQI,47
39
41
  omserv/server/protocols/h11.py,sha256=_q_paD-ff0AWJEPaNK-6MUsQVtYRiALnWGwFyM3D0KU,11976
40
42
  omserv/server/protocols/h2.py,sha256=bC-qmRQqgLASL1DtF3UX1ozximHH4xtae1d_vN2PffY,15345
@@ -46,9 +48,9 @@ omserv/server/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
46
48
  omserv/server/streams/httpstream.py,sha256=0DeiAPLGbEGNa0fHTs8lUpi_CFZs4M5_QB-TiS8mobQ,8015
47
49
  omserv/server/streams/utils.py,sha256=aMOrqWIg_Hht5W4kLg3y7oR5AEkVvMrZhyjzo6U5owE,1527
48
50
  omserv/server/streams/wsstream.py,sha256=3Vyzox7dCE1tDSXjb6xBubWo41ZF9d38Hrsrlj6h1J8,15482
49
- omserv-0.0.0.dev178.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
50
- omserv-0.0.0.dev178.dist-info/METADATA,sha256=iSjP6SCagrTPDQ19CabyHggG1If-DAx_PX3whq-cdFg,983
51
- omserv-0.0.0.dev178.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
52
- omserv-0.0.0.dev178.dist-info/entry_points.txt,sha256=ivSrdA_ahEbI-eVMu-XZS-z4VrnQISvpecIkOqC9zFM,35
53
- omserv-0.0.0.dev178.dist-info/top_level.txt,sha256=HXehpnxeKscKNULzKNzZ27oNawBrsh1PaNAirbX-XNA,7
54
- omserv-0.0.0.dev178.dist-info/RECORD,,
51
+ omserv-0.0.0.dev180.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
52
+ omserv-0.0.0.dev180.dist-info/METADATA,sha256=G9BjZTOQunW07Memp7ZnURvbgResx-uwHHlWgglPpcM,983
53
+ omserv-0.0.0.dev180.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
54
+ omserv-0.0.0.dev180.dist-info/entry_points.txt,sha256=ivSrdA_ahEbI-eVMu-XZS-z4VrnQISvpecIkOqC9zFM,35
55
+ omserv-0.0.0.dev180.dist-info/top_level.txt,sha256=HXehpnxeKscKNULzKNzZ27oNawBrsh1PaNAirbX-XNA,7
56
+ omserv-0.0.0.dev180.dist-info/RECORD,,