omserv 0.0.0.dev160__py3-none-any.whl → 0.0.0.dev217__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
omserv/nginx/__init__.py CHANGED
@@ -0,0 +1,4 @@
1
+ """
2
+ TODO:
3
+ - https://github.com/yandex/gixy
4
+ """
omserv/nginx/build.py CHANGED
@@ -1,3 +1,7 @@
1
+ """
2
+ TODO:
3
+ - https://github.com/webserver-llc/angie ?
4
+ """
1
5
  import multiprocessing as mp
2
6
  import os.path
3
7
  import shutil
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
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: omserv
3
- Version: 0.0.0.dev160
3
+ Version: 0.0.0.dev217
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.dev160
15
+ Requires-Dist: omlish==0.0.0.dev217
16
16
  Provides-Extra: all
17
17
  Requires-Dist: h11~=0.14; extra == "all"
18
18
  Requires-Dist: h2~=4.1; extra == "all"
@@ -9,32 +9,33 @@ omserv/apps/routes.py,sha256=shcN8qCSF2YoKal7nk-lemCAK3RX8MuHgNHhq_CTnh0,3762
9
9
  omserv/apps/sessions.py,sha256=glruQSbOSbCYLPp6nDRNSHCyp5hj4oiOPhh3R0F9BTM,1537
10
10
  omserv/apps/templates.py,sha256=PBRZHIF9UbnFnq-4EC6RmPeRkeH8lCBbpJkSdseHs6A,2125
11
11
  omserv/daemon/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- omserv/nginx/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- omserv/nginx/build.py,sha256=GdDOB3_yLIBKsm6DDcCv7FfajB5-G7x75JcFOgW9CVM,3145
14
- omserv/nginx/configs.py,sha256=4oQDcKJKIatRG621qiZCYTayJI3-vv63TtRCiUxEVWI,2008
12
+ omserv/nginx/__init__.py,sha256=2d63LCGFA2qS7gdl2nCvNPmQWXNICu19wZIihQJPHCs,48
13
+ omserv/nginx/build.py,sha256=2LzI5eM3U2V0CbUHEOHx4zwnMl5CU2lhu-odPrI7idU,3203
15
14
  omserv/nginx/logs.py,sha256=cODPsG1j3EQiXbb9SR20NpB9MjGdWN0ArFZ-TA9xf-c,1840
16
15
  omserv/nginx/stubstatus.py,sha256=_VnXZdXxSA7jIelYSwJLf9mOnt_UOvpWghAPWtlWSLw,1857
17
16
  omserv/nginx/patches/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
17
  omserv/nginx/patches/nginx-1.27.3_http_status.patch,sha256=bEDSczpBLcdjcBp_X1m73oxvt8KPeons7v_sUxqBSXM,4335
19
- omserv/node/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- omserv/node/models.py,sha256=EOaq-aW1rbGOzHTmTULhbVwV5j_burL07qh2QO9smdM,1273
21
- omserv/node/registry.py,sha256=y67VMowll9IuLiTVgauAcbP8-evFJNqpwocwwt7kZL4,3478
22
- omserv/node/sql.py,sha256=vy7RP50JiH3jQHMVa7Hxk0pFJK3QcbGeTvyNppB1W4I,2826
18
+ omserv/nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ omserv/nodes/models.py,sha256=EOaq-aW1rbGOzHTmTULhbVwV5j_burL07qh2QO9smdM,1273
20
+ omserv/nodes/registry.py,sha256=y67VMowll9IuLiTVgauAcbP8-evFJNqpwocwwt7kZL4,3478
21
+ omserv/nodes/sql.py,sha256=vy7RP50JiH3jQHMVa7Hxk0pFJK3QcbGeTvyNppB1W4I,2826
23
22
  omserv/server/LICENSE,sha256=VKPNmbyrS9wcwcx20hBlVtLP01brb2dByHrWHeNLPag,1050
24
- omserv/server/__init__.py,sha256=7c9pUvoC-3lByJeGoQfAcp78JCZ9oA5wP0Bzpm87D7Y,372
23
+ omserv/server/__init__.py,sha256=jrFdrxfnQwjK5DW5y9w0alw6IKToGn2IQyZDhsuGHv4,372
25
24
  omserv/server/config.py,sha256=oGWL1kuk45bJ6sVr8n3ow5Q-1nz9EqByjoykU2iOHIY,1189
26
25
  omserv/server/debug.py,sha256=N7RI0Jj-ttmys3DJD0RREmGG5XZpTCp6y9Yu0x98Agg,299
26
+ omserv/server/default.py,sha256=hmfy--Q35QFMU8oTf4uHwVM2qBFG8mQDR9Wik2f1yZk,970
27
27
  omserv/server/events.py,sha256=VMr_rArsVjJYnyH9SqLWtOLUg18vSu1O0ep9gNBGR_c,1369
28
28
  omserv/server/headers.py,sha256=3H-NxMMQg5WuF5wF4AWFUEqkToh4NqNqHouavzbOQok,1188
29
+ omserv/server/inject.py,sha256=mD3MIDd44_nr1mIiDfjzgJ4DCBeD3JILN6STTDNReGc,454
29
30
  omserv/server/lifespans.py,sha256=kRVxDQM18jCBzRUpafyb69q_bGSCyxxjAtrkxjqcZdE,4607
30
- omserv/server/multiprocess.py,sha256=jKmQzj_Nrwxw2mM-Tf3XVf6vPYMbfyCkPOUWVe028Q8,4253
31
+ omserv/server/listener.py,sha256=t_wUlS6pXnRn-aEXV8D8jhWAeIlQ3a3Sx9i_0BOKV70,7033
32
+ omserv/server/multiprocess.py,sha256=qvNFQEMpTXXR5ACdja4JVC0HFgdvb8CL94iKLDYvZ48,4253
33
+ omserv/server/server.py,sha256=hgUTfZAUwF7V-HdsdV98KbYmE1IRKmEO3B1LlKTiPWc,5223
31
34
  omserv/server/sockets.py,sha256=lwqNP7URlp605ibsjHzp0pc-lyjcyTu-hD-uyojLUYk,3389
32
35
  omserv/server/ssl.py,sha256=gmB5ecM8Mck-YtGYF8pb2dwFdjABVGzERFCDzM9lBck,1483
33
36
  omserv/server/taskspawner.py,sha256=ljzF26UPtnp7GLAY_BvjzuwCoCO9aL7TKLwRNTmUy1M,3008
34
- omserv/server/tcpserver.py,sha256=akC-2WOhmoIiJBH0Ti0m1uK_sOTBYGie0CoRkEcUmkA,5082
35
37
  omserv/server/types.py,sha256=XXY5py8RYlEeD4FZrWNqSyX7DD-ffSlcG-T2s9BY9eI,2017
36
38
  omserv/server/workercontext.py,sha256=4rcLuGsyiU7URO7T_eHylOBPPNUS9C23QfEUVyJUtIY,1200
37
- omserv/server/workers.py,sha256=rdV8qEzWKMZ6HnN9nUoGS58U9LRsrsqOcAd_7yl73Y0,6586
38
39
  omserv/server/protocols/__init__.py,sha256=Ryu2PDZ1TUI6F2l-HBEYgyzZ7wHqE6VmjqnS0tIvmQI,47
39
40
  omserv/server/protocols/h11.py,sha256=_q_paD-ff0AWJEPaNK-6MUsQVtYRiALnWGwFyM3D0KU,11976
40
41
  omserv/server/protocols/h2.py,sha256=bC-qmRQqgLASL1DtF3UX1ozximHH4xtae1d_vN2PffY,15345
@@ -46,9 +47,9 @@ omserv/server/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
46
47
  omserv/server/streams/httpstream.py,sha256=0DeiAPLGbEGNa0fHTs8lUpi_CFZs4M5_QB-TiS8mobQ,8015
47
48
  omserv/server/streams/utils.py,sha256=aMOrqWIg_Hht5W4kLg3y7oR5AEkVvMrZhyjzo6U5owE,1527
48
49
  omserv/server/streams/wsstream.py,sha256=3Vyzox7dCE1tDSXjb6xBubWo41ZF9d38Hrsrlj6h1J8,15482
49
- omserv-0.0.0.dev160.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
50
- omserv-0.0.0.dev160.dist-info/METADATA,sha256=C8Z6OMHBH1YEbR4ZntGe0e7_cJNjrNDc1TE72QDWkmE,983
51
- omserv-0.0.0.dev160.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
52
- omserv-0.0.0.dev160.dist-info/entry_points.txt,sha256=ivSrdA_ahEbI-eVMu-XZS-z4VrnQISvpecIkOqC9zFM,35
53
- omserv-0.0.0.dev160.dist-info/top_level.txt,sha256=HXehpnxeKscKNULzKNzZ27oNawBrsh1PaNAirbX-XNA,7
54
- omserv-0.0.0.dev160.dist-info/RECORD,,
50
+ omserv-0.0.0.dev217.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
51
+ omserv-0.0.0.dev217.dist-info/METADATA,sha256=3cNDxomCex8x0ACSXMvztFjBrNg0xl_jn5U6G-Rc7WI,983
52
+ omserv-0.0.0.dev217.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
53
+ omserv-0.0.0.dev217.dist-info/entry_points.txt,sha256=ivSrdA_ahEbI-eVMu-XZS-z4VrnQISvpecIkOqC9zFM,35
54
+ omserv-0.0.0.dev217.dist-info/top_level.txt,sha256=HXehpnxeKscKNULzKNzZ27oNawBrsh1PaNAirbX-XNA,7
55
+ omserv-0.0.0.dev217.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
omserv/nginx/configs.py DELETED
@@ -1,86 +0,0 @@
1
- """
2
- TODO:
3
- - omnibus/jmespath
4
-
5
- https://nginx.org/en/docs/dev/development_guide.html
6
- https://nginx.org/en/docs/dev/development_guide.html#config_directives
7
- https://nginx.org/en/docs/example.html
8
-
9
- https://github.com/yandex/gixy
10
- """
11
- import dataclasses as dc
12
- import typing as ta
13
-
14
- from omlish import check
15
- from omlish import lang
16
- from omlish.text.indent import IndentWriter
17
-
18
-
19
- @dc.dataclass()
20
- class Items(lang.Final):
21
- lst: list['Item']
22
-
23
- @classmethod
24
- def of(cls, obj: ta.Any) -> 'Items':
25
- if isinstance(obj, Items):
26
- return obj
27
- return cls([Item.of(e) for e in check.isinstance(obj, list)])
28
-
29
-
30
- @dc.dataclass()
31
- class Item(lang.Final):
32
- name: str
33
- args: list[str] | None = None
34
- block: Items | None = None
35
-
36
- @classmethod
37
- def of(cls, obj: ta.Any) -> 'Item':
38
- if isinstance(obj, Item):
39
- return obj
40
- args = check.isinstance(obj, tuple)
41
- name, args = check.isinstance(args[0], str), args[1:]
42
- if args and not isinstance(args[-1], str):
43
- block, args = Items.of(args[-1]), args[:-1]
44
- else:
45
- block = None
46
- return Item(name, [check.isinstance(e, str) for e in args], block=block)
47
-
48
-
49
- def render(wr: IndentWriter, obj: ta.Any) -> None:
50
- if isinstance(obj, Item):
51
- wr.write(obj.name)
52
- for e in obj.args or ():
53
- wr.write(' ')
54
- wr.write(e)
55
- if obj.block:
56
- wr.write(' {\n')
57
- with wr.indent():
58
- render(wr, obj.block)
59
- wr.write('}\n')
60
- else:
61
- wr.write(';\n')
62
-
63
- elif isinstance(obj, Items):
64
- for e2 in obj.lst:
65
- render(wr, e2)
66
-
67
- else:
68
- raise TypeError(obj)
69
-
70
-
71
- def _main() -> None:
72
- conf = Items.of([
73
- ('user', 'www', 'www'),
74
- ('worker_processes', '2'),
75
- ('events', [
76
- ('worker_connections', '2000'),
77
- ]),
78
- ])
79
-
80
- wr = IndentWriter()
81
- render(wr, conf)
82
- print(wr.getvalue())
83
-
84
-
85
- if __name__ == '__main__':
86
- _main()
File without changes
File without changes
File without changes
File without changes