mrok 0.5.0__py3-none-any.whl → 0.7.0__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.
Files changed (47) hide show
  1. mrok/agent/devtools/inspector/__main__.py +2 -24
  2. mrok/agent/devtools/inspector/app.py +408 -113
  3. mrok/agent/devtools/inspector/utils.py +149 -0
  4. mrok/agent/sidecar/app.py +9 -9
  5. mrok/agent/sidecar/main.py +31 -5
  6. mrok/agent/ziticorn.py +8 -2
  7. mrok/cli/commands/admin/bootstrap.py +3 -2
  8. mrok/cli/commands/admin/utils.py +2 -2
  9. mrok/cli/commands/agent/run/sidecar.py +59 -1
  10. mrok/cli/commands/frontend/run.py +43 -1
  11. mrok/cli/main.py +17 -1
  12. mrok/constants.py +21 -0
  13. mrok/controller/schemas.py +2 -2
  14. mrok/frontend/app.py +8 -8
  15. mrok/frontend/main.py +9 -1
  16. mrok/logging.py +0 -22
  17. mrok/proxy/app.py +10 -9
  18. mrok/proxy/asgi.py +96 -0
  19. mrok/proxy/backend.py +5 -3
  20. mrok/proxy/event_publisher.py +66 -0
  21. mrok/proxy/master.py +18 -60
  22. mrok/proxy/metrics.py +2 -2
  23. mrok/proxy/{middlewares.py → middleware.py} +11 -42
  24. mrok/proxy/{datastructures.py → models.py} +43 -17
  25. mrok/proxy/{streams.py → stream.py} +24 -1
  26. mrok/proxy/worker.py +64 -0
  27. mrok/proxy/ziticorn.py +76 -0
  28. mrok/types/__init__.py +0 -0
  29. mrok/{proxy/types.py → types/proxy.py} +7 -2
  30. mrok/types/ziti.py +1 -0
  31. mrok/ziti/api.py +16 -19
  32. mrok/ziti/bootstrap.py +3 -7
  33. mrok/ziti/identities.py +15 -13
  34. mrok/ziti/services.py +3 -2
  35. {mrok-0.5.0.dist-info → mrok-0.7.0.dist-info}/METADATA +8 -2
  36. {mrok-0.5.0.dist-info → mrok-0.7.0.dist-info}/RECORD +39 -40
  37. mrok/agent/devtools/__main__.py +0 -34
  38. mrok/cli/commands/agent/utils.py +0 -5
  39. mrok/proxy/config.py +0 -62
  40. mrok/proxy/constants.py +0 -22
  41. mrok/proxy/lifespan.py +0 -10
  42. mrok/proxy/protocol.py +0 -11
  43. mrok/proxy/server.py +0 -14
  44. mrok/proxy/utils.py +0 -90
  45. {mrok-0.5.0.dist-info → mrok-0.7.0.dist-info}/WHEEL +0 -0
  46. {mrok-0.5.0.dist-info → mrok-0.7.0.dist-info}/entry_points.txt +0 -0
  47. {mrok-0.5.0.dist-info → mrok-0.7.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -0,0 +1,149 @@
1
+ from collections.abc import Generator
2
+ from dataclasses import dataclass
3
+ from io import BytesIO
4
+
5
+ from multipart import MultipartParser
6
+
7
+ TEXTUAL_CONTENT_TYPES = {
8
+ "application/json",
9
+ "application/xml",
10
+ "application/javascript",
11
+ "application/x-www-form-urlencoded",
12
+ }
13
+
14
+ TEXTUAL_PREFIXES = ("text/",)
15
+
16
+ CONTENT_TYPE_TO_LANGUAGE = {
17
+ "application/json": "json",
18
+ "application/ld+json": "json",
19
+ "application/problem+json": "json",
20
+ "application/schema+json": "json",
21
+ "application/xml": "xml",
22
+ "text/xml": "xml",
23
+ "application/xhtml+xml": "html",
24
+ "text/html": "html",
25
+ "text/css": "css",
26
+ "application/javascript": "javascript",
27
+ "application/x-javascript": "javascript",
28
+ "text/javascript": "javascript",
29
+ "application/ecmascript": "javascript",
30
+ "text/markdown": "markdown",
31
+ "text/x-markdown": "markdown",
32
+ "application/yaml": "yaml",
33
+ "application/x-yaml": "yaml",
34
+ "text/yaml": "yaml",
35
+ "application/toml": "toml",
36
+ "application/x-toml": "toml",
37
+ "application/sql": "sql",
38
+ "text/x-sql": "sql",
39
+ "application/java": "java",
40
+ "text/x-java-source": "java",
41
+ "application/python": "python",
42
+ "text/x-python": "python",
43
+ "application/x-python-code": "python",
44
+ "application/rust": "rust",
45
+ "text/x-rust": "rust",
46
+ "application/go": "go",
47
+ "text/x-go": "go",
48
+ "application/bash": "bash",
49
+ "application/x-sh": "bash",
50
+ "text/x-shellscript": "bash",
51
+ "application/regex": "regex",
52
+ "text/x-regex": "regex",
53
+ }
54
+
55
+
56
+ @dataclass
57
+ class ContentTypeInfo:
58
+ content_type: str
59
+ binary: bool
60
+ charset: str | None = None
61
+ boundary: str | None = None
62
+
63
+
64
+ def parse_content_type(content_type_header: str) -> ContentTypeInfo:
65
+ parts = content_type_header.split(";")
66
+ content_type = parts[0].strip().lower()
67
+
68
+ charset = None
69
+ boundary = None
70
+
71
+ for part in parts[1:]:
72
+ part = part.strip()
73
+ if "=" in part:
74
+ key, value = part.split("=", 1)
75
+ key = key.strip().lower()
76
+ value = value.strip().strip('"')
77
+ if key == "charset":
78
+ charset = value
79
+ elif key == "boundary":
80
+ boundary = value
81
+
82
+ binary = not is_textual(content_type)
83
+
84
+ if charset is None and not binary:
85
+ charset = "utf-8"
86
+
87
+ return ContentTypeInfo(
88
+ content_type=content_type, binary=binary, charset=charset, boundary=boundary
89
+ )
90
+
91
+
92
+ def parse_form_data(data: bytes, boundary: str) -> Generator[tuple[str, str]]:
93
+ parser = MultipartParser(BytesIO(data), boundary)
94
+ for part in parser:
95
+ if is_textual(part.content_type):
96
+ yield part.name, part.value
97
+ continue
98
+ yield part.name, "<binary>"
99
+
100
+
101
+ def is_textual(content_type: str) -> bool:
102
+ ct = content_type.lower()
103
+ if ct in TEXTUAL_CONTENT_TYPES:
104
+ return True
105
+ if any(ct.startswith(p) for p in TEXTUAL_PREFIXES):
106
+ return True
107
+ return False
108
+
109
+
110
+ def build_tree(node, data):
111
+ if isinstance(data, dict):
112
+ for key, value in data.items():
113
+ child = node.add(str(key))
114
+ build_tree(child, value)
115
+ elif isinstance(data, list):
116
+ for index, value in enumerate(data):
117
+ child = node.add(f"[{index}]")
118
+ build_tree(child, value)
119
+ else:
120
+ node.add(repr(data))
121
+
122
+
123
+ def hexdump(data, width=16):
124
+ lines = []
125
+ for i in range(0, len(data), width):
126
+ chunk = data[i : i + width]
127
+ hex_part = " ".join(f"{b:02x}" for b in chunk)
128
+ ascii_part = "".join(chr(b) if 32 <= b <= 126 else "." for b in chunk)
129
+ lines.append(f"{hex_part:<{width * 3}} {ascii_part}")
130
+ return "\n".join(lines)
131
+
132
+
133
+ def humanize_bytes(num_bytes: int) -> tuple[float, str]: # type: ignore[return-value]
134
+ if num_bytes < 0:
135
+ raise ValueError("num_bytes must be non-negative")
136
+
137
+ units = ["B", "KiB", "MiB", "GiB", "TiB", "PiB"]
138
+ value = float(num_bytes)
139
+
140
+ for unit in units:
141
+ if value < 1024 or unit == units[-1]:
142
+ return round(value, 2), unit
143
+ value /= 1024
144
+
145
+
146
+ def get_highlighter_language_by_content_type(content_type: str) -> str | None:
147
+ if content_type in CONTENT_TYPE_TO_LANGUAGE:
148
+ return CONTENT_TYPE_TO_LANGUAGE[content_type]
149
+ return None
mrok/agent/sidecar/app.py CHANGED
@@ -5,7 +5,7 @@ from typing import Literal
5
5
  from httpcore import AsyncConnectionPool
6
6
 
7
7
  from mrok.proxy.app import ProxyAppBase
8
- from mrok.proxy.types import Scope
8
+ from mrok.types.proxy import Scope
9
9
 
10
10
  logger = logging.getLogger("mrok.agent")
11
11
 
@@ -18,10 +18,10 @@ class SidecarProxyApp(ProxyAppBase):
18
18
  self,
19
19
  target: str | Path | tuple[str, int],
20
20
  *,
21
- max_connections=1000,
22
- max_keepalive_connections=10,
23
- keepalive_expiry=120,
24
- retries=0,
21
+ max_connections: int | None = 10,
22
+ max_keepalive_connections: int | None = None,
23
+ keepalive_expiry: float | None = None,
24
+ retries: int = 0,
25
25
  ):
26
26
  self._target = target
27
27
  self._target_type, self._target_address = self._parse_target()
@@ -34,10 +34,10 @@ class SidecarProxyApp(ProxyAppBase):
34
34
 
35
35
  def setup_connection_pool(
36
36
  self,
37
- max_connections: int | None = 1000,
38
- max_keepalive_connections: int | None = 10,
39
- keepalive_expiry: float | None = 120.0,
40
- retries: int = 0,
37
+ max_connections: int | None,
38
+ max_keepalive_connections: int | None,
39
+ keepalive_expiry: float | None,
40
+ retries: int,
41
41
  ) -> AsyncConnectionPool:
42
42
  if self._target_type == "unix":
43
43
  return AsyncConnectionPool(
@@ -13,26 +13,47 @@ class SidecarAgent(MasterBase):
13
13
  identity_file: str,
14
14
  target: str | Path | tuple[str, int],
15
15
  workers: int = 4,
16
+ events_enabled: bool = True,
17
+ max_connections: int | None = 10,
18
+ max_keepalive_connections: int | None = None,
19
+ keepalive_expiry: float | None = None,
20
+ retries: int = 0,
16
21
  publishers_port: int = 50000,
17
22
  subscribers_port: int = 50001,
18
23
  ):
19
24
  super().__init__(
20
25
  identity_file,
21
- workers,
22
- False,
23
- publishers_port,
24
- subscribers_port,
26
+ workers=workers,
27
+ reload=False,
28
+ events_enabled=events_enabled,
29
+ events_pub_port=publishers_port,
30
+ events_sub_port=subscribers_port,
25
31
  )
26
32
  self._target = target
33
+ self._max_connections = max_connections
34
+ self._max_keepalive_connections = max_keepalive_connections
35
+ self._keepalive_expiry = keepalive_expiry
36
+ self._retries = retries
27
37
 
28
38
  def get_asgi_app(self):
29
- return SidecarProxyApp(self._target)
39
+ return SidecarProxyApp(
40
+ self._target,
41
+ max_connections=self._max_connections,
42
+ max_keepalive_connections=self._max_keepalive_connections,
43
+ keepalive_expiry=self._keepalive_expiry,
44
+ retries=self._retries,
45
+ )
30
46
 
31
47
 
32
48
  def run(
33
49
  identity_file: str,
34
50
  target_addr: str | Path | tuple[str, int],
35
51
  workers: int = 4,
52
+ events_enabled: bool = True,
53
+ max_connections: int | None = 10,
54
+ max_keepalive_connections: int | None = None,
55
+ keepalive_expiry: float | None = None,
56
+ retries: int = 0,
36
57
  publishers_port: int = 50000,
37
58
  subscribers_port: int = 50001,
38
59
  ):
@@ -40,6 +61,11 @@ def run(
40
61
  identity_file,
41
62
  target_addr,
42
63
  workers=workers,
64
+ events_enabled=events_enabled,
65
+ max_connections=max_connections,
66
+ max_keepalive_connections=max_keepalive_connections,
67
+ keepalive_expiry=keepalive_expiry,
68
+ retries=retries,
43
69
  publishers_port=publishers_port,
44
70
  subscribers_port=subscribers_port,
45
71
  )
mrok/agent/ziticorn.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from mrok.proxy.master import MasterBase
2
- from mrok.proxy.types import ASGIApp
2
+ from mrok.types.proxy import ASGIApp
3
3
 
4
4
 
5
5
  class ZiticornAgent(MasterBase):
@@ -12,7 +12,13 @@ class ZiticornAgent(MasterBase):
12
12
  publishers_port: int = 50000,
13
13
  subscribers_port: int = 50001,
14
14
  ):
15
- super().__init__(identity_file, workers, reload, publishers_port, subscribers_port)
15
+ super().__init__(
16
+ identity_file,
17
+ workers=workers,
18
+ reload=reload,
19
+ events_pub_port=publishers_port,
20
+ events_sub_port=subscribers_port,
21
+ )
16
22
  self.app = app
17
23
 
18
24
  def get_asgi_app(self):
@@ -8,14 +8,15 @@ import typer
8
8
 
9
9
  from mrok.cli.commands.admin.utils import parse_tags
10
10
  from mrok.conf import Settings
11
- from mrok.ziti.api import TagsType, ZitiClientAPI, ZitiManagementAPI
11
+ from mrok.types.ziti import Tags
12
+ from mrok.ziti.api import ZitiClientAPI, ZitiManagementAPI
12
13
  from mrok.ziti.bootstrap import bootstrap_identity
13
14
 
14
15
  logger = logging.getLogger(__name__)
15
16
 
16
17
 
17
18
  async def bootstrap(
18
- settings: Settings, forced: bool, tags: TagsType | None
19
+ settings: Settings, forced: bool, tags: Tags | None
19
20
  ) -> tuple[str, dict[str, Any] | None]:
20
21
  async with ZitiManagementAPI(settings) as mgmt_api, ZitiClientAPI(settings) as client_api:
21
22
  return await bootstrap_identity(
@@ -2,10 +2,10 @@ from datetime import datetime
2
2
 
3
3
  import typer
4
4
 
5
- from mrok.ziti.api import TagsType
5
+ from mrok.types.ziti import Tags
6
6
 
7
7
 
8
- def parse_tags(pairs: list[str] | None) -> TagsType | None:
8
+ def parse_tags(pairs: list[str] | None) -> Tags | None:
9
9
  if not pairs:
10
10
  return None
11
11
 
@@ -25,10 +25,55 @@ def register(app: typer.Typer) -> None:
25
25
  typer.Option(
26
26
  "--workers",
27
27
  "-w",
28
- help=f"Number of workers. Default: {default_workers}",
28
+ help="Number of workers.",
29
29
  show_default=True,
30
30
  ),
31
31
  ] = default_workers,
32
+ max_connections: Annotated[
33
+ int,
34
+ typer.Option(
35
+ "--max-pool-connections",
36
+ help=(
37
+ "The maximum number of concurrent HTTP connections that "
38
+ "the pool should allow. Any attempt to send a request on a pool that "
39
+ "would exceed this amount will block until a connection is available."
40
+ ),
41
+ show_default=True,
42
+ ),
43
+ ] = 10,
44
+ max_keepalive_connections: Annotated[
45
+ int | None,
46
+ typer.Option(
47
+ "--max-pool-keepalive-connections",
48
+ help=(
49
+ "The maximum number of idle HTTP connections "
50
+ "that will be maintained in the pool."
51
+ ),
52
+ show_default=True,
53
+ ),
54
+ ] = None,
55
+ keepalive_expiry: Annotated[
56
+ float | None,
57
+ typer.Option(
58
+ "--max-pool-keepalive-expiry",
59
+ help=(
60
+ "The duration in seconds that an idle HTTP connection "
61
+ "may be maintained for before being expired from the pool."
62
+ ),
63
+ show_default=True,
64
+ ),
65
+ ] = None,
66
+ retries: Annotated[
67
+ int,
68
+ typer.Option(
69
+ "--max-pool-connect-retries",
70
+ help=(
71
+ "The duration in seconds that an idle HTTP connection "
72
+ "may be maintained for before being expired from the pool."
73
+ ),
74
+ show_default=True,
75
+ ),
76
+ ] = 0,
32
77
  publishers_port: Annotated[
33
78
  int,
34
79
  typer.Option(
@@ -53,6 +98,14 @@ def register(app: typer.Typer) -> None:
53
98
  show_default=True,
54
99
  ),
55
100
  ] = 50001,
101
+ no_events: Annotated[
102
+ bool,
103
+ typer.Option(
104
+ "--no-events",
105
+ help="Disable events. Default: False",
106
+ show_default=True,
107
+ ),
108
+ ] = False,
56
109
  ):
57
110
  """Run a Sidecar Proxy to expose a web application through OpenZiti."""
58
111
  if ":" in str(target):
@@ -65,6 +118,11 @@ def register(app: typer.Typer) -> None:
65
118
  str(identity_file),
66
119
  target_addr,
67
120
  workers=workers,
121
+ events_enabled=not no_events,
122
+ max_connections=max_connections,
123
+ max_keepalive_connections=max_keepalive_connections,
124
+ keepalive_expiry=keepalive_expiry,
125
+ retries=retries,
68
126
  publishers_port=publishers_port,
69
127
  subscribers_port=subscribers_port,
70
128
  )
@@ -44,6 +44,48 @@ def register(app: typer.Typer) -> None:
44
44
  show_default=True,
45
45
  ),
46
46
  ] = default_workers,
47
+ max_connections: Annotated[
48
+ int,
49
+ typer.Option(
50
+ "--max-pool-connections",
51
+ help=(
52
+ "The maximum number of concurrent HTTP connections that "
53
+ "the pool should allow. Any attempt to send a request on a pool that "
54
+ "would exceed this amount will block until a connection is available."
55
+ ),
56
+ show_default=True,
57
+ ),
58
+ ] = 1000,
59
+ max_keepalive_connections: Annotated[
60
+ int | None,
61
+ typer.Option(
62
+ "--max-pool-keepalive-connections",
63
+ help=(
64
+ "The maximum number of idle HTTP connections "
65
+ "that will be maintained in the pool."
66
+ ),
67
+ show_default=True,
68
+ ),
69
+ ] = 100,
70
+ keepalive_expiry: Annotated[
71
+ float | None,
72
+ typer.Option(
73
+ "--max-pool-keepalive-expiry",
74
+ help=(
75
+ "The duration in seconds that an idle HTTP connection "
76
+ "may be maintained for before being expired from the pool."
77
+ ),
78
+ show_default=True,
79
+ ),
80
+ ] = 300,
47
81
  ):
48
82
  """Run the mrok frontend with Gunicorn and Uvicorn workers."""
49
- frontend.run(identity_file, host, port, workers)
83
+ frontend.run(
84
+ identity_file,
85
+ host,
86
+ port,
87
+ workers,
88
+ max_connections=max_connections,
89
+ max_keepalive_connections=max_keepalive_connections,
90
+ keepalive_expiry=keepalive_expiry,
91
+ )
mrok/cli/main.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import inspect
2
2
  import sys
3
+ from typing import Annotated
3
4
 
4
5
  import typer
5
6
  from pyfiglet import Figlet
@@ -79,11 +80,23 @@ for name, module in inspect.getmembers(commands):
79
80
  elif hasattr(module, "app"): # pragma: no branch
80
81
  app.add_typer(module.app, name=name.replace("_", "-"))
81
82
 
83
+ _debug_mode = False
84
+
82
85
 
83
86
  @app.callback()
84
87
  def main(
85
88
  ctx: typer.Context,
89
+ debug: Annotated[
90
+ bool,
91
+ typer.Option(
92
+ "--debug",
93
+ help="Run the CLI in debug mode",
94
+ show_default=True,
95
+ ),
96
+ ] = False,
86
97
  ):
98
+ global _debug_mode
99
+ _debug_mode = debug
87
100
  settings = get_settings()
88
101
  setup_logging(settings, cli_mode=True)
89
102
  ctx.obj = settings
@@ -93,5 +106,8 @@ def run():
93
106
  try:
94
107
  app()
95
108
  except Exception as e:
96
- err_console.print(f"[bold red]Error:[/bold red] {e}")
109
+ if _debug_mode:
110
+ raise
111
+ message = str(e) or "Unexpected error. Debug it with --debug"
112
+ err_console.print(f"[bold red]Error:[/bold red] {message}")
97
113
  sys.exit(-1)
mrok/constants.py CHANGED
@@ -2,3 +2,24 @@ import re
2
2
 
3
3
  RE_EXTENSION_ID = re.compile(r"(?i)EXT-\d{4}-\d{4}")
4
4
  RE_INSTANCE_ID = re.compile(r"(?i)INS-\d{4}-\d{4}-\d{4}")
5
+
6
+
7
+ BINARY_CONTENT_TYPES = {
8
+ "application/octet-stream",
9
+ "application/pdf",
10
+ }
11
+
12
+ BINARY_PREFIXES = (
13
+ "image/",
14
+ "video/",
15
+ "audio/",
16
+ )
17
+
18
+ TEXTUAL_CONTENT_TYPES = {
19
+ "application/json",
20
+ "application/xml",
21
+ "application/javascript",
22
+ "application/x-www-form-urlencoded",
23
+ }
24
+
25
+ TEXTUAL_PREFIXES = ("text/",)
@@ -9,12 +9,12 @@ from pydantic import (
9
9
  computed_field,
10
10
  )
11
11
 
12
- from mrok.ziti.api import TagsType
12
+ from mrok.types.ziti import Tags
13
13
 
14
14
 
15
15
  class BaseSchema(BaseModel):
16
16
  model_config = ConfigDict(from_attributes=True, extra="ignore")
17
- tags: TagsType | None = None
17
+ tags: Tags | None = None
18
18
 
19
19
 
20
20
  class IdSchema(BaseModel):
mrok/frontend/app.py CHANGED
@@ -6,7 +6,7 @@ from mrok.conf import get_settings
6
6
  from mrok.proxy.app import ProxyAppBase
7
7
  from mrok.proxy.backend import AIOZitiNetworkBackend
8
8
  from mrok.proxy.exceptions import InvalidTargetError
9
- from mrok.proxy.types import Scope
9
+ from mrok.types.proxy import Scope
10
10
 
11
11
  RE_SUBDOMAIN = re.compile(r"(?i)^(?:EXT-\d{4}-\d{4}|INS-\d{4}-\d{4}-\d{4})$")
12
12
 
@@ -16,9 +16,9 @@ class FrontendProxyApp(ProxyAppBase):
16
16
  self,
17
17
  identity_file: str,
18
18
  *,
19
- max_connections: int = 1000,
20
- max_keepalive_connections: int = 10,
21
- keepalive_expiry: float = 120.0,
19
+ max_connections: int | None = 10,
20
+ max_keepalive_connections: int | None = None,
21
+ keepalive_expiry: float | None = None,
22
22
  retries=0,
23
23
  ):
24
24
  self._identity_file = identity_file
@@ -32,10 +32,10 @@ class FrontendProxyApp(ProxyAppBase):
32
32
 
33
33
  def setup_connection_pool(
34
34
  self,
35
- max_connections: int | None = 1000,
36
- max_keepalive_connections: int | None = 100,
37
- keepalive_expiry: float | None = 120.0,
38
- retries: int = 0,
35
+ max_connections: int | None,
36
+ max_keepalive_connections: int | None,
37
+ keepalive_expiry: float | None,
38
+ retries: int,
39
39
  ) -> AsyncConnectionPool:
40
40
  return AsyncConnectionPool(
41
41
  max_connections=max_connections,
mrok/frontend/main.py CHANGED
@@ -38,8 +38,16 @@ def run(
38
38
  host: str,
39
39
  port: int,
40
40
  workers: int,
41
+ max_connections: int | None,
42
+ max_keepalive_connections: int | None,
43
+ keepalive_expiry: float | None,
41
44
  ):
42
- app = FrontendProxyApp(str(identity_file))
45
+ app = FrontendProxyApp(
46
+ str(identity_file),
47
+ max_connections=max_connections,
48
+ max_keepalive_connections=max_keepalive_connections,
49
+ keepalive_expiry=keepalive_expiry,
50
+ )
43
51
 
44
52
  options = {
45
53
  "bind": f"{host}:{port}",
mrok/logging.py CHANGED
@@ -1,9 +1,5 @@
1
1
  import logging.config
2
2
 
3
- from rich.console import Console
4
- from rich.logging import RichHandler
5
- from textual_serve.server import LogHighlighter
6
-
7
3
  from mrok.conf import Settings
8
4
 
9
5
 
@@ -78,21 +74,3 @@ def get_logging_config(settings: Settings, cli_mode: bool = False) -> dict:
78
74
  def setup_logging(settings: Settings, cli_mode: bool = False) -> None:
79
75
  logging_config = get_logging_config(settings, cli_mode)
80
76
  logging.config.dictConfig(logging_config)
81
-
82
-
83
- def setup_inspector_logging(console: Console) -> None:
84
- logging.basicConfig(
85
- level="WARNING",
86
- format="%(message)s",
87
- datefmt="%Y-%m-%d %H:%M:%S",
88
- handlers=[
89
- RichHandler(
90
- show_path=False,
91
- show_time=True,
92
- rich_tracebacks=True,
93
- tracebacks_show_locals=True,
94
- highlighter=LogHighlighter(),
95
- console=console,
96
- )
97
- ],
98
- )
mrok/proxy/app.py CHANGED
@@ -4,8 +4,8 @@ import logging
4
4
  from httpcore import AsyncConnectionPool, Request
5
5
 
6
6
  from mrok.proxy.exceptions import ProxyError
7
- from mrok.proxy.streams import ASGIRequestBodyStream
8
- from mrok.proxy.types import ASGIReceive, ASGISend, Scope
7
+ from mrok.proxy.stream import ASGIRequestBodyStream
8
+ from mrok.types.proxy import ASGIReceive, ASGISend, Scope
9
9
 
10
10
  logger = logging.getLogger("mrok.proxy")
11
11
 
@@ -26,9 +26,9 @@ class ProxyAppBase(abc.ABC):
26
26
  def __init__(
27
27
  self,
28
28
  *,
29
- max_connections: int | None = 1000,
30
- max_keepalive_connections: int | None = 10,
31
- keepalive_expiry: float | None = 120.0,
29
+ max_connections: int | None = 10,
30
+ max_keepalive_connections: int | None = None,
31
+ keepalive_expiry: float | None = None,
32
32
  retries: int = 0,
33
33
  ) -> None:
34
34
  self._pool = self.setup_connection_pool(
@@ -41,10 +41,10 @@ class ProxyAppBase(abc.ABC):
41
41
  @abc.abstractmethod
42
42
  def setup_connection_pool(
43
43
  self,
44
- max_connections: int | None = 1000,
45
- max_keepalive_connections: int | None = 10,
46
- keepalive_expiry: float | None = 120.0,
47
- retries: int = 0,
44
+ max_connections: int | None,
45
+ max_keepalive_connections: int | None,
46
+ keepalive_expiry: float | None,
47
+ retries: int,
48
48
  ) -> AsyncConnectionPool:
49
49
  raise NotImplementedError()
50
50
 
@@ -78,6 +78,7 @@ class ProxyAppBase(abc.ABC):
78
78
  content=body_stream,
79
79
  )
80
80
  response = await self._pool.handle_async_request(request)
81
+ logger.debug(f"connection pool status: {self._pool}")
81
82
  response_headers = []
82
83
  for k, v in response.headers:
83
84
  if k.lower() not in HOP_BY_HOP_HEADERS: