mcp-proxy-adapter 6.7.2__py3-none-any.whl → 6.8.1__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.
- mcp_proxy_adapter/api/app.py +30 -46
- mcp_proxy_adapter/core/app_factory.py +41 -55
- mcp_proxy_adapter/core/mtls_server.py +5 -1
- mcp_proxy_adapter/core/signal_handler.py +6 -4
- mcp_proxy_adapter/core/utils.py +142 -0
- mcp_proxy_adapter/examples/basic_framework/main.py +10 -11
- mcp_proxy_adapter/examples/full_application/main.py +12 -62
- mcp_proxy_adapter/main.py +22 -0
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.7.2.dist-info → mcp_proxy_adapter-6.8.1.dist-info}/METADATA +1 -1
- {mcp_proxy_adapter-6.7.2.dist-info → mcp_proxy_adapter-6.8.1.dist-info}/RECORD +14 -16
- mcp_proxy_adapter/core/async_proxy_registration.py +0 -285
- mcp_proxy_adapter/examples/generate_certificates.py +0 -385
- {mcp_proxy_adapter-6.7.2.dist-info → mcp_proxy_adapter-6.8.1.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.7.2.dist-info → mcp_proxy_adapter-6.8.1.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.7.2.dist-info → mcp_proxy_adapter-6.8.1.dist-info}/top_level.txt +0 -0
@@ -2,11 +2,11 @@ mcp_proxy_adapter/__init__.py,sha256=iH0EBBsRj_cfZJpAIsgN_8tTdfefhnl6uUKHjLHhWDQ
|
|
2
2
|
mcp_proxy_adapter/__main__.py,sha256=sq3tANRuTd18euamt0Bmn1sJeAyzXENZ5VvsMwbrDFA,579
|
3
3
|
mcp_proxy_adapter/config.py,sha256=QpoPaUKcWJ-eu6HYphhIZmkc2M-p1JgpLFAgolf_l5s,20161
|
4
4
|
mcp_proxy_adapter/custom_openapi.py,sha256=XRviX-C-ZkSKdBhORhDTdeN_1FWyEfXZADiASft3t9I,28149
|
5
|
-
mcp_proxy_adapter/main.py,sha256=
|
5
|
+
mcp_proxy_adapter/main.py,sha256=NFcSW7WaEnimRWe5zj28D0CH9otHlRZ92d2Um6XiGjE,10399
|
6
6
|
mcp_proxy_adapter/openapi.py,sha256=2UZOI09ZDRJuBYBjKbMyb2U4uASszoCMD5o_4ktRpvg,13480
|
7
|
-
mcp_proxy_adapter/version.py,sha256
|
7
|
+
mcp_proxy_adapter/version.py,sha256=-XyUUimtSI9hGbSPyEYlJ4Xr-Gug_CLJLv0ilk_TFeE,74
|
8
8
|
mcp_proxy_adapter/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
-
mcp_proxy_adapter/api/app.py,sha256=
|
9
|
+
mcp_proxy_adapter/api/app.py,sha256=PQ1Ch5ydJIHp3Z6gcMCzKkTsXPQAuZ9weHtQ-EXnNGY,37134
|
10
10
|
mcp_proxy_adapter/api/handlers.py,sha256=X-hcMNVeTAu4yVkKJEChEsj2bFptUS6sLNN-Wysjkow,10011
|
11
11
|
mcp_proxy_adapter/api/schemas.py,sha256=mevUvQnYgWQfkJAs3-vq3HalBzh6-Saa-Au1VVf0peE,12377
|
12
12
|
mcp_proxy_adapter/api/tool_integration.py,sha256=AeUyvJVN-c3FrX5fHdagHL51saRH5d1ZKqc2YEx0rTE,10147
|
@@ -54,9 +54,8 @@ mcp_proxy_adapter/commands/token_management_command.py,sha256=tCVjhWqAQ3KhcwSsZU
|
|
54
54
|
mcp_proxy_adapter/commands/transport_management_command.py,sha256=HEnUyL4S014jheyBwO90u9gnzk0qxBlOJdC_0Sxhq9E,4585
|
55
55
|
mcp_proxy_adapter/commands/unload_command.py,sha256=6CUM9B9c-mNxw7uvt2vcvZSnxMySfoMT5UmDhzNXq38,4984
|
56
56
|
mcp_proxy_adapter/core/__init__.py,sha256=3yt0CFZdsIG8Ln4bg-r4ISYzipm3ZUAxTn0twYTs9FI,867
|
57
|
-
mcp_proxy_adapter/core/app_factory.py,sha256=
|
57
|
+
mcp_proxy_adapter/core/app_factory.py,sha256=OuxUjGpOp5mOPIQ5iumBW42bxAD0H6o2HM8UICgpUvA,20492
|
58
58
|
mcp_proxy_adapter/core/app_runner.py,sha256=n8_rBojzKUpHLN5ksiXcR8UWoBYk6Tt5OtWk-X2kVPc,11868
|
59
|
-
mcp_proxy_adapter/core/async_proxy_registration.py,sha256=hM_ZV2YoKM8n0MakVMBd2KnYTJBh1igDeb4DYutfHnE,11387
|
60
59
|
mcp_proxy_adapter/core/auth_validator.py,sha256=q8TNkdolvP-gM6Bvecc6nrVG9al5J31pocdwhguhTBk,19742
|
61
60
|
mcp_proxy_adapter/core/certificate_utils.py,sha256=yeDwi-j42CxK_g-r5_ragGFY_HdSgDfTWHVUjDHF6nI,38480
|
62
61
|
mcp_proxy_adapter/core/client.py,sha256=qIbPl8prEwK2U65kl-vGJW2_imo1E4i6HxG_VpPeWpQ,21168
|
@@ -70,7 +69,7 @@ mcp_proxy_adapter/core/logging.py,sha256=gNI6vfPQC7jrUtVu6NeDsmU72JPlrRRBhtJipL1
|
|
70
69
|
mcp_proxy_adapter/core/mtls_asgi.py,sha256=tvk0P9024s18dcCHY9AaQIecT4ojOTv21EuQWXwooU0,5200
|
71
70
|
mcp_proxy_adapter/core/mtls_asgi_app.py,sha256=DT_fTUH1RkvBa3ThbyCyNb-XUHyCb4DqaKA1gcZC6z4,6538
|
72
71
|
mcp_proxy_adapter/core/mtls_proxy.py,sha256=5APlWs0ImiHGEC65W_7F-PbVO3NZ2BVSj9r14AcUtTE,6011
|
73
|
-
mcp_proxy_adapter/core/mtls_server.py,sha256=
|
72
|
+
mcp_proxy_adapter/core/mtls_server.py,sha256=GBNhLezDYSXFP1xcNaThEhBqZlxXUGp0q0OT2Ibb2M0,10366
|
74
73
|
mcp_proxy_adapter/core/protocol_manager.py,sha256=iaXWsfm1XSfemz5QQBesMluc4cwf-LtuZVi9bm1uj28,14680
|
75
74
|
mcp_proxy_adapter/core/proxy_client.py,sha256=CB6KBhV3vH2GU5nZ27VZ_xlNbYTAU_tnYFrkuK5He58,6094
|
76
75
|
mcp_proxy_adapter/core/proxy_registration.py,sha256=QlQFHnjIN8ETWcasPDUXNMfMsU_-KdrvLTYJiDua_wI,41237
|
@@ -81,11 +80,11 @@ mcp_proxy_adapter/core/security_integration.py,sha256=-5I4i9so_yMjc-zuGO-7zzIsMX
|
|
81
80
|
mcp_proxy_adapter/core/server_adapter.py,sha256=jz8ztIfe82N5DE3XHRYpD6CwNcJy7ksh0l8l-towHBE,9755
|
82
81
|
mcp_proxy_adapter/core/server_engine.py,sha256=qmxdkBv-YsQsvxVVQ-_xiAyDshxtnrKBquPJoUjo2fw,9471
|
83
82
|
mcp_proxy_adapter/core/settings.py,sha256=D6cF4R_5gJ0XFGxzXUIzeqe-_muu6HL561TAei9wwZ0,10521
|
84
|
-
mcp_proxy_adapter/core/signal_handler.py,sha256=
|
83
|
+
mcp_proxy_adapter/core/signal_handler.py,sha256=TwBftsPAkMNcCSrE1ZA5qKnazcCVRpt_UGQzn6ITDHQ,5327
|
85
84
|
mcp_proxy_adapter/core/ssl_utils.py,sha256=Rjl79d5LdhDzxiMtaIRd9OFh0hTeRANItYFXk-7c5pA,9498
|
86
85
|
mcp_proxy_adapter/core/transport_manager.py,sha256=eJbGa3gDVFUBFUzMK5KEmpbUDXOOShtzszUIEf7Jk0A,9292
|
87
86
|
mcp_proxy_adapter/core/unified_config_adapter.py,sha256=zBGYdLDZ3G8f3Y9tmtm0Ne0UXIfEaNHR4Ik2W3ErkLc,22814
|
88
|
-
mcp_proxy_adapter/core/utils.py,sha256=
|
87
|
+
mcp_proxy_adapter/core/utils.py,sha256=StTL44fNXYcQfIwc68LTNTDgjyQ0feGCsYSBI0ly6qE,8047
|
89
88
|
mcp_proxy_adapter/examples/__init__.py,sha256=k1F-EotAFbJ3JvK_rNgiH4bUztmxIWtYn0AfbAZ1ZGs,450
|
90
89
|
mcp_proxy_adapter/examples/bugfix_certificate_config.py,sha256=YGBE_SI6wYZUJLWl7-fP1OWXiSH4mHJAZHApgQWvG7s,10529
|
91
90
|
mcp_proxy_adapter/examples/cert_manager_bugfix.py,sha256=UWUwItjqHqSnOMHocsz40_3deoZE8-vdROLW9y2fEns,7259
|
@@ -96,7 +95,6 @@ mcp_proxy_adapter/examples/create_test_configs.py,sha256=9TrvLa4-bWLPu0SB1JXwWuC
|
|
96
95
|
mcp_proxy_adapter/examples/debug_request_state.py,sha256=Z3Gy2-fWtu7KIV9OkzGDLVz7TpL_h9V_99ica40uQBU,4489
|
97
96
|
mcp_proxy_adapter/examples/debug_role_chain.py,sha256=GLVXC2fJUwP8UJnXHchd1t-H53cjWLJI3RqTPrKmaak,8750
|
98
97
|
mcp_proxy_adapter/examples/demo_client.py,sha256=en2Rtb70B1sQmhL-vdQ4PDpKNNl_mfll2YCFT_jFCAg,10191
|
99
|
-
mcp_proxy_adapter/examples/generate_certificates.py,sha256=cIfTHBziGiOTy9vldAmaULD6bXBpl2a5KfB8MLIRSww,16391
|
100
98
|
mcp_proxy_adapter/examples/generate_config.py,sha256=9zImMfIM88OQz12mE5k0_RnVV5ZmhlIKO2fRldiNCok,12709
|
101
99
|
mcp_proxy_adapter/examples/proxy_registration_example.py,sha256=vemRhftnjbiOBCJkmtDGqlWQ8syTG0a8755GCOnaQsg,12503
|
102
100
|
mcp_proxy_adapter/examples/required_certificates.py,sha256=YW9-V78oFiZ-FmHlGP-8FQFS569VdDVyq9hfvCv31pk,7133
|
@@ -117,12 +115,12 @@ mcp_proxy_adapter/examples/test_protocol_examples.py,sha256=yCZzZrJ9ICXMkF1bAMoz
|
|
117
115
|
mcp_proxy_adapter/examples/universal_client.py,sha256=n1-cBPOiCipA86Zcc_mI_jMywDMZS1p3u5JT3AqTsrQ,27577
|
118
116
|
mcp_proxy_adapter/examples/update_config_certificates.py,sha256=ObGF5oNQ9OStryUvFDXxrN-olRMKdSOrl5KSwARF7EY,4608
|
119
117
|
mcp_proxy_adapter/examples/basic_framework/__init__.py,sha256=4aYD--R6hy9n9CUxj7Osb9HcdVUMJ6_cfpu4ujkbCwI,345
|
120
|
-
mcp_proxy_adapter/examples/basic_framework/main.py,sha256=
|
118
|
+
mcp_proxy_adapter/examples/basic_framework/main.py,sha256=2bpT-zrekpzzbhOx6wOOYXYE1mejWXkT617zpSN7m70,1790
|
121
119
|
mcp_proxy_adapter/examples/basic_framework/commands/__init__.py,sha256=_VQNLUEdsxUG-4yt9BZI_vtOxHAdGG0OUSsP6Wj-Vz4,76
|
122
120
|
mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py,sha256=IE_EIXMnkdXuakZn7wLD9kBFyfDF5lYi56ejgiBeb-A,70
|
123
121
|
mcp_proxy_adapter/examples/commands/__init__.py,sha256=zvY_OpH_B1bVc_khrNIl6O8vqCw1FH6gGMAsJAkGWGY,170
|
124
122
|
mcp_proxy_adapter/examples/full_application/__init__.py,sha256=xGiPYhRAzs1Fh9wA8HoowV-Gg9QMLaMZn-OamExq1TI,320
|
125
|
-
mcp_proxy_adapter/examples/full_application/main.py,sha256=
|
123
|
+
mcp_proxy_adapter/examples/full_application/main.py,sha256=ZJmXe6WU-4q-U0AKIAdDm9HNREBgWwZz26ohY511xHs,5603
|
126
124
|
mcp_proxy_adapter/examples/full_application/proxy_endpoints.py,sha256=Kt_WAsG61HLTMkKQ1mQqjvlX9I4TcfwYq0NaRR9HKvM,6179
|
127
125
|
mcp_proxy_adapter/examples/full_application/commands/__init__.py,sha256=yQHxVSFkAyFLUOdk42QOebUODPlQV9IbydPgF3UKsGM,217
|
128
126
|
mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py,sha256=H7FPJmVJNWT61rPWxep06-7hsYRt8XYBUSBiwqpBurU,3096
|
@@ -134,8 +132,8 @@ mcp_proxy_adapter/schemas/base_schema.json,sha256=v9G9cGMd4dRhCZsOQ_FMqOi5VFyVbI
|
|
134
132
|
mcp_proxy_adapter/schemas/openapi_schema.json,sha256=C3yLkwmDsvnLW9B5gnKKdBGl4zxkeU-rEmjTrNVsQU0,8405
|
135
133
|
mcp_proxy_adapter/schemas/roles.json,sha256=pgf_ZyqKyXbfGUxvobpiLiSJz9zzxrMuoVWEkEpz3N8,764
|
136
134
|
mcp_proxy_adapter/schemas/roles_schema.json,sha256=deHgI7L6GwfBXacOlNtDgDJelDThppClC3Ti4Eh8rJY,5659
|
137
|
-
mcp_proxy_adapter-6.
|
138
|
-
mcp_proxy_adapter-6.
|
139
|
-
mcp_proxy_adapter-6.
|
140
|
-
mcp_proxy_adapter-6.
|
141
|
-
mcp_proxy_adapter-6.
|
135
|
+
mcp_proxy_adapter-6.8.1.dist-info/METADATA,sha256=UBdAIcl991nJLgTUGFiYNu73PxbGb-j6a0phDbMzreE,8510
|
136
|
+
mcp_proxy_adapter-6.8.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
137
|
+
mcp_proxy_adapter-6.8.1.dist-info/entry_points.txt,sha256=Bf-O5Aq80n22Ayu9fI9BgidzWqwzIVaqextAddTuHZw,563
|
138
|
+
mcp_proxy_adapter-6.8.1.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
|
139
|
+
mcp_proxy_adapter-6.8.1.dist-info/RECORD,,
|
@@ -1,285 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Asynchronous proxy registration with heartbeat functionality.
|
3
|
-
|
4
|
-
This module provides automatic proxy registration in a separate thread
|
5
|
-
with continuous heartbeat monitoring and automatic re-registration on failures.
|
6
|
-
|
7
|
-
Author: Vasiliy Zdanovskiy
|
8
|
-
email: vasilyvz@gmail.com
|
9
|
-
"""
|
10
|
-
|
11
|
-
import asyncio
|
12
|
-
import time
|
13
|
-
import threading
|
14
|
-
from typing import Dict, Any, Optional
|
15
|
-
from dataclasses import dataclass
|
16
|
-
from enum import Enum
|
17
|
-
|
18
|
-
from mcp_proxy_adapter.core.logging import logger
|
19
|
-
from mcp_proxy_adapter.core.proxy_registration import ProxyRegistrationManager
|
20
|
-
|
21
|
-
|
22
|
-
class RegistrationState(Enum):
|
23
|
-
"""Registration state enumeration."""
|
24
|
-
DISABLED = "disabled"
|
25
|
-
NOT_REGISTERED = "not_registered"
|
26
|
-
REGISTERING = "registering"
|
27
|
-
REGISTERED = "registered"
|
28
|
-
HEARTBEAT_FAILED = "heartbeat_failed"
|
29
|
-
ERROR = "error"
|
30
|
-
|
31
|
-
|
32
|
-
@dataclass
|
33
|
-
class RegistrationStatus:
|
34
|
-
"""Registration status information."""
|
35
|
-
state: RegistrationState
|
36
|
-
server_key: Optional[str] = None
|
37
|
-
last_attempt: Optional[float] = None
|
38
|
-
last_success: Optional[float] = None
|
39
|
-
last_error: Optional[str] = None
|
40
|
-
attempt_count: int = 0
|
41
|
-
success_count: int = 0
|
42
|
-
|
43
|
-
|
44
|
-
class AsyncProxyRegistrationManager:
|
45
|
-
"""
|
46
|
-
Asynchronous proxy registration manager with heartbeat functionality.
|
47
|
-
|
48
|
-
Runs registration and heartbeat in a separate thread, automatically
|
49
|
-
handling re-registration on failures and continuous monitoring.
|
50
|
-
"""
|
51
|
-
|
52
|
-
def __init__(self, config: Dict[str, Any]):
|
53
|
-
"""
|
54
|
-
Initialize the async proxy registration manager.
|
55
|
-
|
56
|
-
Args:
|
57
|
-
config: Application configuration
|
58
|
-
"""
|
59
|
-
self.config = config
|
60
|
-
self.registration_manager = ProxyRegistrationManager(config)
|
61
|
-
self.status = RegistrationStatus(state=RegistrationState.NOT_REGISTERED)
|
62
|
-
self._thread: Optional[threading.Thread] = None
|
63
|
-
self._stop_event = threading.Event()
|
64
|
-
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
65
|
-
|
66
|
-
# Get heartbeat configuration
|
67
|
-
heartbeat_config = config.get("registration", {}).get("heartbeat", {})
|
68
|
-
self.heartbeat_enabled = heartbeat_config.get("enabled", True)
|
69
|
-
self.heartbeat_interval = heartbeat_config.get("interval", 30)
|
70
|
-
self.heartbeat_timeout = heartbeat_config.get("timeout", 10)
|
71
|
-
self.retry_attempts = heartbeat_config.get("retry_attempts", 3)
|
72
|
-
self.retry_delay = heartbeat_config.get("retry_delay", 5)
|
73
|
-
|
74
|
-
logger.info(f"AsyncProxyRegistrationManager initialized: heartbeat_enabled={self.heartbeat_enabled}, interval={self.heartbeat_interval}s")
|
75
|
-
|
76
|
-
def is_enabled(self) -> bool:
|
77
|
-
"""Check if proxy registration is enabled."""
|
78
|
-
return self.registration_manager.is_enabled()
|
79
|
-
|
80
|
-
def set_server_url(self, server_url: str):
|
81
|
-
"""Set the server URL for registration."""
|
82
|
-
self.registration_manager.set_server_url(server_url)
|
83
|
-
logger.info(f"Server URL set for async registration: {server_url}")
|
84
|
-
|
85
|
-
def start(self):
|
86
|
-
"""Start the async registration and heartbeat thread."""
|
87
|
-
if not self.is_enabled():
|
88
|
-
logger.info("Proxy registration is disabled, not starting async manager")
|
89
|
-
self.status.state = RegistrationState.DISABLED
|
90
|
-
return
|
91
|
-
|
92
|
-
if self._thread and self._thread.is_alive():
|
93
|
-
logger.warning("Async registration thread is already running")
|
94
|
-
return
|
95
|
-
|
96
|
-
logger.info("Starting async proxy registration and heartbeat thread")
|
97
|
-
self._stop_event.clear()
|
98
|
-
self._thread = threading.Thread(target=self._run_async_loop, daemon=True)
|
99
|
-
self._thread.start()
|
100
|
-
|
101
|
-
def stop(self):
|
102
|
-
"""Stop the async registration and heartbeat thread."""
|
103
|
-
if not self._thread or not self._thread.is_alive():
|
104
|
-
return
|
105
|
-
|
106
|
-
logger.info("Stopping async proxy registration and heartbeat thread")
|
107
|
-
self._stop_event.set()
|
108
|
-
|
109
|
-
# Unregister if registered
|
110
|
-
if self.status.state == RegistrationState.REGISTERED:
|
111
|
-
try:
|
112
|
-
# Run unregistration in the thread's event loop
|
113
|
-
if self._loop and not self._loop.is_closed():
|
114
|
-
future = asyncio.run_coroutine_threadsafe(
|
115
|
-
self.registration_manager.unregister_server(),
|
116
|
-
self._loop
|
117
|
-
)
|
118
|
-
future.result(timeout=10)
|
119
|
-
logger.info("Successfully unregistered from proxy during shutdown")
|
120
|
-
except Exception as e:
|
121
|
-
logger.error(f"Failed to unregister during shutdown: {e}")
|
122
|
-
|
123
|
-
self._thread.join(timeout=5)
|
124
|
-
if self._thread.is_alive():
|
125
|
-
logger.warning("Async registration thread did not stop gracefully")
|
126
|
-
|
127
|
-
def _run_async_loop(self):
|
128
|
-
"""Run the async event loop in the thread."""
|
129
|
-
try:
|
130
|
-
self._loop = asyncio.new_event_loop()
|
131
|
-
asyncio.set_event_loop(self._loop)
|
132
|
-
self._loop.run_until_complete(self._async_main())
|
133
|
-
except Exception as e:
|
134
|
-
logger.error(f"Async registration loop error: {e}")
|
135
|
-
finally:
|
136
|
-
if self._loop and not self._loop.is_closed():
|
137
|
-
self._loop.close()
|
138
|
-
|
139
|
-
async def _async_main(self):
|
140
|
-
"""Main async loop for registration and heartbeat."""
|
141
|
-
logger.info("Async registration loop started")
|
142
|
-
|
143
|
-
# Initial registration attempt
|
144
|
-
await self._attempt_registration()
|
145
|
-
|
146
|
-
# Main loop
|
147
|
-
while not self._stop_event.is_set():
|
148
|
-
try:
|
149
|
-
if self.status.state == RegistrationState.REGISTERED:
|
150
|
-
if self.heartbeat_enabled:
|
151
|
-
# Perform heartbeat
|
152
|
-
await self._perform_heartbeat()
|
153
|
-
else:
|
154
|
-
# Just wait if heartbeat is disabled
|
155
|
-
await asyncio.sleep(self.heartbeat_interval)
|
156
|
-
else:
|
157
|
-
# Try to register
|
158
|
-
await self._attempt_registration()
|
159
|
-
# Wait before retry
|
160
|
-
await asyncio.sleep(self.retry_delay)
|
161
|
-
|
162
|
-
except Exception as e:
|
163
|
-
logger.error(f"Error in async registration loop: {e}")
|
164
|
-
self.status.state = RegistrationState.ERROR
|
165
|
-
self.status.last_error = str(e)
|
166
|
-
await asyncio.sleep(self.retry_delay)
|
167
|
-
|
168
|
-
logger.info("Async registration loop stopped")
|
169
|
-
|
170
|
-
async def _attempt_registration(self):
|
171
|
-
"""Attempt to register with the proxy."""
|
172
|
-
if self.status.state == RegistrationState.REGISTERING:
|
173
|
-
return # Already registering
|
174
|
-
|
175
|
-
self.status.state = RegistrationState.REGISTERING
|
176
|
-
self.status.attempt_count += 1
|
177
|
-
self.status.last_attempt = time.time()
|
178
|
-
|
179
|
-
logger.info(f"Attempting proxy registration (attempt #{self.status.attempt_count})")
|
180
|
-
|
181
|
-
try:
|
182
|
-
success = await self.registration_manager.register_server()
|
183
|
-
|
184
|
-
if success:
|
185
|
-
self.status.state = RegistrationState.REGISTERED
|
186
|
-
self.status.last_success = time.time()
|
187
|
-
self.status.success_count += 1
|
188
|
-
self.status.last_error = None
|
189
|
-
logger.info(f"✅ Proxy registration successful (attempt #{self.status.attempt_count})")
|
190
|
-
else:
|
191
|
-
self.status.state = RegistrationState.NOT_REGISTERED
|
192
|
-
self.status.last_error = "Registration returned False"
|
193
|
-
logger.warning(f"❌ Proxy registration failed (attempt #{self.status.attempt_count}): Registration returned False")
|
194
|
-
|
195
|
-
except Exception as e:
|
196
|
-
self.status.state = RegistrationState.NOT_REGISTERED
|
197
|
-
self.status.last_error = str(e)
|
198
|
-
logger.error(f"❌ Proxy registration failed (attempt #{self.status.attempt_count}): {e}")
|
199
|
-
|
200
|
-
async def _perform_heartbeat(self):
|
201
|
-
"""Perform heartbeat to the proxy."""
|
202
|
-
try:
|
203
|
-
# Use the registration manager's heartbeat functionality
|
204
|
-
success = await self.registration_manager.heartbeat()
|
205
|
-
|
206
|
-
if success:
|
207
|
-
logger.debug("💓 Heartbeat successful")
|
208
|
-
self.status.last_success = time.time()
|
209
|
-
else:
|
210
|
-
logger.warning("💓 Heartbeat failed")
|
211
|
-
self.status.state = RegistrationState.HEARTBEAT_FAILED
|
212
|
-
self.status.last_error = "Heartbeat failed"
|
213
|
-
|
214
|
-
# Try to re-register after heartbeat failure
|
215
|
-
logger.info("Attempting re-registration after heartbeat failure")
|
216
|
-
await self._attempt_registration()
|
217
|
-
|
218
|
-
except Exception as e:
|
219
|
-
logger.error(f"💓 Heartbeat error: {e}")
|
220
|
-
self.status.state = RegistrationState.HEARTBEAT_FAILED
|
221
|
-
self.status.last_error = str(e)
|
222
|
-
|
223
|
-
# Try to re-register after heartbeat error
|
224
|
-
logger.info("Attempting re-registration after heartbeat error")
|
225
|
-
await self._attempt_registration()
|
226
|
-
|
227
|
-
# Wait for next heartbeat
|
228
|
-
await asyncio.sleep(self.heartbeat_interval)
|
229
|
-
|
230
|
-
def get_status(self) -> Dict[str, Any]:
|
231
|
-
"""Get current registration status."""
|
232
|
-
return {
|
233
|
-
"state": self.status.state.value,
|
234
|
-
"server_key": self.status.server_key,
|
235
|
-
"last_attempt": self.status.last_attempt,
|
236
|
-
"last_success": self.status.last_success,
|
237
|
-
"last_error": self.status.last_error,
|
238
|
-
"attempt_count": self.status.attempt_count,
|
239
|
-
"success_count": self.status.success_count,
|
240
|
-
"heartbeat_enabled": self.heartbeat_enabled,
|
241
|
-
"heartbeat_interval": self.heartbeat_interval,
|
242
|
-
"thread_alive": self._thread.is_alive() if self._thread else False
|
243
|
-
}
|
244
|
-
|
245
|
-
|
246
|
-
# Global instance
|
247
|
-
_async_registration_manager: Optional[AsyncProxyRegistrationManager] = None
|
248
|
-
|
249
|
-
|
250
|
-
def get_async_registration_manager() -> Optional[AsyncProxyRegistrationManager]:
|
251
|
-
"""Get the global async registration manager instance."""
|
252
|
-
return _async_registration_manager
|
253
|
-
|
254
|
-
|
255
|
-
def initialize_async_registration(config: Dict[str, Any]) -> AsyncProxyRegistrationManager:
|
256
|
-
"""Initialize the global async registration manager."""
|
257
|
-
global _async_registration_manager
|
258
|
-
_async_registration_manager = AsyncProxyRegistrationManager(config)
|
259
|
-
return _async_registration_manager
|
260
|
-
|
261
|
-
|
262
|
-
def start_async_registration(server_url: str):
|
263
|
-
"""Start async registration with the given server URL."""
|
264
|
-
global _async_registration_manager
|
265
|
-
if _async_registration_manager:
|
266
|
-
_async_registration_manager.set_server_url(server_url)
|
267
|
-
_async_registration_manager.start()
|
268
|
-
else:
|
269
|
-
logger.error("Async registration manager not initialized")
|
270
|
-
|
271
|
-
|
272
|
-
def stop_async_registration():
|
273
|
-
"""Stop async registration."""
|
274
|
-
global _async_registration_manager
|
275
|
-
if _async_registration_manager:
|
276
|
-
_async_registration_manager.stop()
|
277
|
-
|
278
|
-
|
279
|
-
def get_registration_status() -> Dict[str, Any]:
|
280
|
-
"""Get current registration status."""
|
281
|
-
global _async_registration_manager
|
282
|
-
if _async_registration_manager:
|
283
|
-
return _async_registration_manager.get_status()
|
284
|
-
else:
|
285
|
-
return {"state": "not_initialized"}
|