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.
@@ -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=ILdGeikcZls2y9Uro0bQLi53FPSuJv_yZBio-3WD2zM,9233
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=8BW2GJtsmlLZwL8XRvuPQimNVnKFme-0iHrLwWsvEpM,74
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=GGhA5X7HQPLJFxeaWHu5YUwi2ldPvPvJD2YcaL9Nbo0,37874
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=Ywq-RN2o5B86nJpqImnaXNf_g366lVK1fXeIbIr49DM,21625
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=_hj6QWuExKX2LRohYvjPGFC2qTutS7ObegpEc09QijM,10117
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=ryL4bLzV6ERrXPx19K4ApFGMzFI8iwlI0timj-GQ1YI,5324
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=wBdDYBDWQ6zbwrnl9tykHjo0FjJVsLT_x8Bjk1lZX60,3270
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=XdGrD_52hhCVHwqx4XmfVmd7tlfp6WE-qZ0gw05SyB0,1792
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=ogL3Bil_5puGnwvMh3YNOjrW76FIzzoggKEp-04HSfo,7855
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.7.2.dist-info/METADATA,sha256=Xg6ENQrj-kv2GZ0TXmwW3OBxzje9tBsWKclciTZDjnE,8510
138
- mcp_proxy_adapter-6.7.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
139
- mcp_proxy_adapter-6.7.2.dist-info/entry_points.txt,sha256=Bf-O5Aq80n22Ayu9fI9BgidzWqwzIVaqextAddTuHZw,563
140
- mcp_proxy_adapter-6.7.2.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
141
- mcp_proxy_adapter-6.7.2.dist-info/RECORD,,
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"}