genai-protocol-lite 1.0.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.
- AIConnector/__init__.py +0 -0
- AIConnector/common/__init__.py +0 -0
- AIConnector/common/exceptions.py +13 -0
- AIConnector/common/logger.py +57 -0
- AIConnector/common/message.py +14 -0
- AIConnector/common/network.py +146 -0
- AIConnector/connector/__init__.py +0 -0
- AIConnector/connector/azure_connector.py +205 -0
- AIConnector/connector/base_connector.py +51 -0
- AIConnector/connector/peer_connection_manager.py +260 -0
- AIConnector/connector/ws_connector.py +213 -0
- AIConnector/core/__init__.py +0 -0
- AIConnector/core/chat_client.py +505 -0
- AIConnector/core/job.py +48 -0
- AIConnector/core/job_manager.py +219 -0
- AIConnector/core/message_factory.py +44 -0
- AIConnector/discovery/__init__.py +0 -0
- AIConnector/discovery/azure_discovery_service.py +206 -0
- AIConnector/discovery/base_discovery_service.py +27 -0
- AIConnector/discovery/discovery_service.py +226 -0
- AIConnector/session.py +274 -0
- genai_protocol_lite-1.0.0.dist-info/METADATA +186 -0
- genai_protocol_lite-1.0.0.dist-info/RECORD +26 -0
- genai_protocol_lite-1.0.0.dist-info/WHEEL +5 -0
- genai_protocol_lite-1.0.0.dist-info/licenses/LICENSE +201 -0
- genai_protocol_lite-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,260 @@
|
|
1
|
+
import asyncio
|
2
|
+
import time
|
3
|
+
import logging
|
4
|
+
from typing import Callable, Optional, Dict, Any, List, Tuple
|
5
|
+
|
6
|
+
from AIConnector.common.network import NetworkConfig
|
7
|
+
from AIConnector.connector.base_connector import BaseConnector
|
8
|
+
from AIConnector.connector.ws_connector import WsConnector
|
9
|
+
from AIConnector.connector.azure_connector import AzureConnector
|
10
|
+
|
11
|
+
from AIConnector.discovery.base_discovery_service import BaseDiscoveryService
|
12
|
+
from AIConnector.discovery.discovery_service import DiscoveryService
|
13
|
+
from AIConnector.discovery.azure_discovery_service import AzureDiscoveryService
|
14
|
+
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
class P2PMeta(type):
|
19
|
+
"""
|
20
|
+
Metaclass for PeerConnectionManager that dynamically sets up the appropriate
|
21
|
+
connector and discovery service based on the network configuration.
|
22
|
+
"""
|
23
|
+
def __call__(cls, *args, **kwargs):
|
24
|
+
# Create the instance using the default __call__ method.
|
25
|
+
instance = super().__call__(*args, **kwargs)
|
26
|
+
connection_type = instance.network_config.connection_type
|
27
|
+
|
28
|
+
if connection_type == "local":
|
29
|
+
# For local connections, use the WebSocket connector and local discovery service.
|
30
|
+
instance.connector = WsConnector(
|
31
|
+
on_message_callback=instance.on_message_callback,
|
32
|
+
on_peer_disconnected=instance.on_peer_disconnected,
|
33
|
+
ssl_context=instance.ssl_context,
|
34
|
+
client_name=instance.client_name,
|
35
|
+
client_id=instance.client_id,
|
36
|
+
)
|
37
|
+
instance.discovery_service = DiscoveryService(
|
38
|
+
on_peer_discovered_callback=instance._on_peer_discovered,
|
39
|
+
on_peer_lost=instance._on_peer_lost,
|
40
|
+
client_name=instance.client_name,
|
41
|
+
port=instance.port,
|
42
|
+
network_config=instance.network_config
|
43
|
+
)
|
44
|
+
else:
|
45
|
+
# For remote connections, use the Azure connector and Azure discovery service.
|
46
|
+
instance.connector = AzureConnector(
|
47
|
+
client_name=instance.client_name,
|
48
|
+
client_id=instance.client_id,
|
49
|
+
azure_endpoint_url=instance.network_config.azure_endpoint_url,
|
50
|
+
azure_access_key=instance.network_config.azure_access_key,
|
51
|
+
azure_api_version=instance.network_config.azure_api_version,
|
52
|
+
on_message_callback=instance.on_message_callback,
|
53
|
+
on_peer_disconnected=instance.on_peer_disconnected
|
54
|
+
)
|
55
|
+
instance.discovery_service = AzureDiscoveryService(
|
56
|
+
client_name=instance.client_name,
|
57
|
+
client_id=instance.client_id,
|
58
|
+
azure_endpoint_url=instance.network_config.azure_endpoint_url,
|
59
|
+
azure_access_key=instance.network_config.azure_access_key,
|
60
|
+
azure_api_version=instance.network_config.azure_api_version,
|
61
|
+
on_peer_discovered_callback=instance._on_peer_discovered,
|
62
|
+
on_peer_lost=instance._on_peer_lost,
|
63
|
+
)
|
64
|
+
|
65
|
+
return instance
|
66
|
+
|
67
|
+
|
68
|
+
class PeerConnectionManager(metaclass=P2PMeta):
|
69
|
+
"""
|
70
|
+
Handles peer-to-peer connectivity using WebSocket connections and a discovery service.
|
71
|
+
|
72
|
+
The connector and discovery service used are determined dynamically based on the
|
73
|
+
provided network configuration. For a local connection type, the connector uses
|
74
|
+
WebSocket-based communication; otherwise, Azure-based implementations are used.
|
75
|
+
"""
|
76
|
+
|
77
|
+
def __init__(
|
78
|
+
self,
|
79
|
+
on_message_callback: Callable[[Dict[str, Any]], None],
|
80
|
+
client_id: str,
|
81
|
+
network_config: NetworkConfig,
|
82
|
+
on_peer_connected: Optional[Callable[[str], None]] = None,
|
83
|
+
on_peer_disconnected: Optional[Callable[[str], None]] = None,
|
84
|
+
on_peer_discovered: Optional[Callable[[str], None]] = None,
|
85
|
+
on_peer_lost: Optional[Callable[[str], None]] = None,
|
86
|
+
ssl_context: Any = None,
|
87
|
+
client_name: Optional[str] = None,
|
88
|
+
port: Optional[int] = None,
|
89
|
+
) -> None:
|
90
|
+
"""
|
91
|
+
Initialize the PeerConnectionManager.
|
92
|
+
|
93
|
+
Args:
|
94
|
+
on_message_callback (Callable[[Dict[str, Any]], None]):
|
95
|
+
Function to call when a message is received.
|
96
|
+
client_id (str): Unique identifier for this client.
|
97
|
+
network_config (NetworkConfig): Network configuration object.
|
98
|
+
on_peer_connected (Optional[Callable[[str], None]], optional):
|
99
|
+
Function to call when a peer connects.
|
100
|
+
on_peer_disconnected (Optional[Callable[[str], None]], optional):
|
101
|
+
Function to call when a peer disconnects.
|
102
|
+
on_peer_discovered (Optional[Callable[[str], None]], optional):
|
103
|
+
Function to call when a new peer is discovered.
|
104
|
+
on_peer_lost (Optional[Callable[[str], None]], optional):
|
105
|
+
Function to call when a peer is lost.
|
106
|
+
ssl_context (Any, optional): SSL context for secure connections.
|
107
|
+
client_name (Optional[str], optional): Client name for identification.
|
108
|
+
port (Optional[int], optional): Port number for discovery broadcasting.
|
109
|
+
"""
|
110
|
+
self.on_message_callback = on_message_callback
|
111
|
+
self.on_peer_connected = on_peer_connected
|
112
|
+
self.on_peer_disconnected = on_peer_disconnected
|
113
|
+
self.on_peer_discovered = on_peer_discovered
|
114
|
+
self.on_peer_lost = on_peer_lost
|
115
|
+
self.ssl_context = ssl_context
|
116
|
+
self.client_name = client_name
|
117
|
+
self.client_id = client_id
|
118
|
+
self.network_config = network_config
|
119
|
+
self.port = port
|
120
|
+
|
121
|
+
self.connector: BaseConnector = None
|
122
|
+
self.discovery_service: BaseDiscoveryService = None
|
123
|
+
|
124
|
+
# Dictionary mapping peer_id to peer info.
|
125
|
+
self.peers: Dict[str, Dict[str, Any]] = {}
|
126
|
+
|
127
|
+
async def start(self, host: str, port: int, allow_discovery: bool) -> None:
|
128
|
+
"""
|
129
|
+
Start the discovery service and the connector's server.
|
130
|
+
|
131
|
+
Args:
|
132
|
+
host (str): Host address to bind the WebSocket server.
|
133
|
+
port (int): Port number to bind the WebSocket server.
|
134
|
+
allow_discovery (bool): Enable or disable the discovery phase.
|
135
|
+
"""
|
136
|
+
await self.discovery_service.start(allow_discovery=allow_discovery)
|
137
|
+
await self.connector.start_server(host=host, port=port, allow_discovery=allow_discovery)
|
138
|
+
logger.debug("[PeerConnectionManager] Started")
|
139
|
+
|
140
|
+
async def stop(self) -> None:
|
141
|
+
"""
|
142
|
+
Stop the discovery service and the connector's server.
|
143
|
+
"""
|
144
|
+
await self.discovery_service.stop()
|
145
|
+
await self.connector.stop_server()
|
146
|
+
logger.debug("[PeerConnectionManager] Stopped")
|
147
|
+
|
148
|
+
async def connect_to_peer(self, ip: str, port: int, peer_id: str) -> None:
|
149
|
+
"""
|
150
|
+
Connect to a discovered peer.
|
151
|
+
|
152
|
+
Args:
|
153
|
+
ip (str): IP address of the peer.
|
154
|
+
port (int): Port number of the peer.
|
155
|
+
peer_id (str): Unique identifier of the peer.
|
156
|
+
"""
|
157
|
+
await self.connector.connect_to_peer(ip, port, peer_id)
|
158
|
+
if self.on_peer_connected:
|
159
|
+
result = self.on_peer_connected(peer_id)
|
160
|
+
if asyncio.iscoroutine(result):
|
161
|
+
await result
|
162
|
+
|
163
|
+
async def send_message(self, peer_id: str, msg: Dict[str, Any]) -> None:
|
164
|
+
"""
|
165
|
+
Send a message to a specific peer.
|
166
|
+
|
167
|
+
Args:
|
168
|
+
peer_id (str): Unique identifier of the recipient peer.
|
169
|
+
msg (Dict[str, Any]): Message content as a dictionary.
|
170
|
+
"""
|
171
|
+
# If no active connection exists, try to establish one using stored peer info.
|
172
|
+
if peer_id not in self.connector.active_connections:
|
173
|
+
peer_info = self.peers.get(peer_id)
|
174
|
+
if peer_info:
|
175
|
+
await self.connect_to_peer(peer_info["ip"], peer_info["port"], peer_id)
|
176
|
+
else:
|
177
|
+
logger.error(f"[PeerConnectionManager] Cannot send message: peer {peer_id} not discovered")
|
178
|
+
return
|
179
|
+
await self.connector.send_message(peer_id, msg)
|
180
|
+
|
181
|
+
async def _on_peer_discovered(self, msg: Dict[str, Any], addr: Tuple[str, int]) -> None:
|
182
|
+
"""
|
183
|
+
Async callback triggered when a new peer is discovered.
|
184
|
+
|
185
|
+
Args:
|
186
|
+
msg (Dict[str, Any]): Message containing peer details.
|
187
|
+
addr (Tuple[str, int]): Tuple with the peer's (IP, port) address.
|
188
|
+
"""
|
189
|
+
peer_id = msg.get("client_id")
|
190
|
+
# Ignore invalid peer IDs or self-discovery.
|
191
|
+
if not peer_id or peer_id == self.client_id:
|
192
|
+
return
|
193
|
+
|
194
|
+
ip = addr[0]
|
195
|
+
port = msg.get("port")
|
196
|
+
name = msg.get("display_name", "Unknown")
|
197
|
+
now = time.time()
|
198
|
+
|
199
|
+
# Add or update the peer in the peers dictionary.
|
200
|
+
if peer_id not in self.peers:
|
201
|
+
self.peers[peer_id] = {
|
202
|
+
"ip": ip,
|
203
|
+
"port": port,
|
204
|
+
"display_name": name,
|
205
|
+
"last_seen": now,
|
206
|
+
}
|
207
|
+
else:
|
208
|
+
self.peers[peer_id].update({
|
209
|
+
"ip": ip,
|
210
|
+
"port": port,
|
211
|
+
"last_seen": now,
|
212
|
+
})
|
213
|
+
|
214
|
+
if self.on_peer_discovered:
|
215
|
+
try:
|
216
|
+
result = self.on_peer_discovered(peer_id)
|
217
|
+
if asyncio.iscoroutine(result):
|
218
|
+
await result
|
219
|
+
except Exception as e:
|
220
|
+
logger.error(f"[PeerConnectionManager] Error in on_peer_discovered callback: {e}")
|
221
|
+
|
222
|
+
async def _on_peer_lost(self, peer_id: str) -> None:
|
223
|
+
"""
|
224
|
+
Async callback triggered when a peer is lost.
|
225
|
+
|
226
|
+
Args:
|
227
|
+
peer_id (str): Unique identifier of the lost peer.
|
228
|
+
"""
|
229
|
+
removed = self.peers.pop(peer_id, None)
|
230
|
+
|
231
|
+
if removed is not None:
|
232
|
+
logger.debug(f"[PeerConnectionManager] Peer {peer_id} removed from peers list")
|
233
|
+
|
234
|
+
if self.on_peer_lost:
|
235
|
+
result = self.on_peer_lost(peer_id)
|
236
|
+
if asyncio.iscoroutine(result):
|
237
|
+
await result
|
238
|
+
|
239
|
+
def get_peers_list(self) -> List[Dict[str, str]]:
|
240
|
+
"""
|
241
|
+
Retrieve a list of discovered peers.
|
242
|
+
|
243
|
+
Returns:
|
244
|
+
List[Dict[str, str]]: A list of dictionaries, each containing 'peer_id' and 'display_name'.
|
245
|
+
"""
|
246
|
+
result = [
|
247
|
+
{"peer_id": pid, "display_name": info["display_name"]}
|
248
|
+
for pid, info in self.peers.items()
|
249
|
+
]
|
250
|
+
logger.info(f"[PeerConnectionManager] Get peers list returned {result}")
|
251
|
+
return result
|
252
|
+
|
253
|
+
async def close_connection(self, peer_id: str):
|
254
|
+
"""
|
255
|
+
Close connection
|
256
|
+
|
257
|
+
Args:
|
258
|
+
peer_id (str): Unique identifier of the lost peer.
|
259
|
+
"""
|
260
|
+
await self.connector.disconnect_from_peer(peer_id)
|
@@ -0,0 +1,213 @@
|
|
1
|
+
import asyncio
|
2
|
+
import json
|
3
|
+
import time
|
4
|
+
import logging
|
5
|
+
|
6
|
+
import websockets
|
7
|
+
from typing import Callable, Optional, Dict, Any
|
8
|
+
|
9
|
+
from AIConnector.connector.base_connector import BaseConnector
|
10
|
+
|
11
|
+
logger = logging.getLogger(__name__)
|
12
|
+
|
13
|
+
|
14
|
+
class WsConnector(BaseConnector):
|
15
|
+
"""
|
16
|
+
Manages WebSocket connections to peers.
|
17
|
+
"""
|
18
|
+
|
19
|
+
def __init__(
|
20
|
+
self,
|
21
|
+
client_id: str,
|
22
|
+
on_message_callback: Callable[[Dict[str, Any]], asyncio.Future],
|
23
|
+
on_peer_connected: Optional[Callable[[str], asyncio.Future]] = None,
|
24
|
+
on_peer_disconnected: Optional[Callable[[str], asyncio.Future]] = None,
|
25
|
+
ssl_context: Optional[Any] = None,
|
26
|
+
client_name: Optional[str] = None,
|
27
|
+
) -> None:
|
28
|
+
"""
|
29
|
+
Initialize the WebSocket connector.
|
30
|
+
|
31
|
+
Args:
|
32
|
+
client_id (str): Unique identifier for this client.
|
33
|
+
on_message_callback (Callable[[Dict[str, Any]], asyncio.Future]):
|
34
|
+
Coroutine to be called with incoming messages.
|
35
|
+
on_peer_connected (Optional[Callable[[str], asyncio.Future]], optional):
|
36
|
+
Coroutine to be called when a peer connects.
|
37
|
+
on_peer_disconnected (Optional[Callable[[str], asyncio.Future]], optional):
|
38
|
+
Coroutine to be called when a peer disconnects.
|
39
|
+
ssl_context (Optional[Any], optional): SSL context for secure connections.
|
40
|
+
client_name (Optional[str], optional): Client name for identification.
|
41
|
+
"""
|
42
|
+
self.client_id = client_id
|
43
|
+
self.on_message_callback = on_message_callback
|
44
|
+
self.on_peer_connected = on_peer_connected
|
45
|
+
self.on_peer_disconnected = on_peer_disconnected
|
46
|
+
self.ssl_context = ssl_context
|
47
|
+
self.client_name = client_name
|
48
|
+
|
49
|
+
# Dictionary to store active WebSocket connections by peer ID.
|
50
|
+
self.active_connections: Dict[str, websockets.WebSocketClientProtocol] = {}
|
51
|
+
self.server: Optional[websockets.server.Serve] = None
|
52
|
+
|
53
|
+
async def start_server(
|
54
|
+
self, host: str = "0.0.0.0", port: int = 5000, allow_discovery: bool = True
|
55
|
+
) -> None:
|
56
|
+
"""
|
57
|
+
Start the WebSocket server.
|
58
|
+
|
59
|
+
Args:
|
60
|
+
host (str): The host address to bind the server.
|
61
|
+
port (int): The port number to bind the server.
|
62
|
+
allow_discovery (bool): If True, start the WebSocket server.
|
63
|
+
"""
|
64
|
+
if not allow_discovery:
|
65
|
+
return
|
66
|
+
|
67
|
+
self.server = await websockets.serve(self._handler, host, port, ssl=self.ssl_context)
|
68
|
+
logger.info(f"[WsConnector] WebSocket server started on {host}:{port}")
|
69
|
+
|
70
|
+
async def stop_server(self) -> None:
|
71
|
+
"""
|
72
|
+
Stop the WebSocket server and close all active connections.
|
73
|
+
"""
|
74
|
+
if self.server:
|
75
|
+
self.server.close()
|
76
|
+
await self.server.wait_closed()
|
77
|
+
logger.info("[WsConnector] Server stopped")
|
78
|
+
|
79
|
+
async def _handler(self, websocket: websockets.WebSocketServerProtocol, path: str = "") -> None:
|
80
|
+
"""
|
81
|
+
Handle incoming WebSocket connections.
|
82
|
+
|
83
|
+
Args:
|
84
|
+
websocket (websockets.WebSocketServerProtocol): The connected WebSocket.
|
85
|
+
path (str): URL path (unused).
|
86
|
+
"""
|
87
|
+
peername = websocket.remote_address
|
88
|
+
logger.info(f"[WsServer] Connection established with {peername}")
|
89
|
+
try:
|
90
|
+
async for message in websocket:
|
91
|
+
try:
|
92
|
+
msg = json.loads(message)
|
93
|
+
except Exception as e:
|
94
|
+
logger.error(f"[WsServer] Error parsing message: {e}")
|
95
|
+
continue
|
96
|
+
|
97
|
+
# Register connection upon receiving a HELLO message.
|
98
|
+
if msg.get("type") == "HELLO":
|
99
|
+
peer_id = msg.get("from_id")
|
100
|
+
if peer_id:
|
101
|
+
self.active_connections[peer_id] = websocket
|
102
|
+
if self.on_peer_connected:
|
103
|
+
await self.on_peer_connected(peer_id)
|
104
|
+
|
105
|
+
# Process the incoming message.
|
106
|
+
await self.on_message_callback(msg)
|
107
|
+
except websockets.exceptions.ConnectionClosed:
|
108
|
+
logger.debug(f"[WsServer] Connection closed: {peername}")
|
109
|
+
finally:
|
110
|
+
# Remove connection from active connections and notify disconnection.
|
111
|
+
for pid, ws in list(self.active_connections.items()):
|
112
|
+
if ws == websocket:
|
113
|
+
del self.active_connections[pid]
|
114
|
+
if self.on_peer_disconnected:
|
115
|
+
await self.on_peer_disconnected(pid)
|
116
|
+
break
|
117
|
+
|
118
|
+
async def connect_to_peer(self, ip: str, port: int, peer_id: str) -> None:
|
119
|
+
"""
|
120
|
+
Connect to a peer using a WebSocket connection.
|
121
|
+
|
122
|
+
Args:
|
123
|
+
ip (str): IP address of the peer.
|
124
|
+
port (int): Port number of the peer.
|
125
|
+
peer_id (str): Unique identifier of the peer.
|
126
|
+
"""
|
127
|
+
if peer_id in self.active_connections:
|
128
|
+
return
|
129
|
+
|
130
|
+
websocket_uri = f"ws://{ip}:{port}"
|
131
|
+
try:
|
132
|
+
websocket = await websockets.connect(websocket_uri, ssl=self.ssl_context)
|
133
|
+
self.active_connections[peer_id] = websocket
|
134
|
+
logger.info(f"[WsConnector] Connected to {peer_id} ({ip}:{port})")
|
135
|
+
|
136
|
+
# Handle messages from the peer asynchronously.
|
137
|
+
asyncio.create_task(self._client_handler(websocket, peer_id))
|
138
|
+
|
139
|
+
# Send a handshake HELLO message.
|
140
|
+
handshake_msg = {
|
141
|
+
"type": "HELLO",
|
142
|
+
"from_id": self.client_id,
|
143
|
+
"from_name": self.client_name or "Unknown",
|
144
|
+
"timestamp": time.time(),
|
145
|
+
}
|
146
|
+
await websocket.send(json.dumps(handshake_msg))
|
147
|
+
except Exception as e:
|
148
|
+
logger.error(f"[WsConnector] Connection error to {ip}:{port} - {e}")
|
149
|
+
|
150
|
+
async def _client_handler(self, websocket: websockets.WebSocketClientProtocol, peer_id: str) -> None:
|
151
|
+
"""
|
152
|
+
Handle messages received from a connected peer.
|
153
|
+
|
154
|
+
Args:
|
155
|
+
websocket (websockets.WebSocketClientProtocol): The peer's WebSocket connection.
|
156
|
+
peer_id (str): Unique identifier of the peer.
|
157
|
+
"""
|
158
|
+
try:
|
159
|
+
async for message in websocket:
|
160
|
+
try:
|
161
|
+
msg = json.loads(message)
|
162
|
+
except Exception as e:
|
163
|
+
logger.error(f"[WsClient] Error parsing message: {e}")
|
164
|
+
continue
|
165
|
+
|
166
|
+
# Update connection info on HELLO messages.
|
167
|
+
if msg.get("type") == "HELLO":
|
168
|
+
p_id = msg.get("from_id")
|
169
|
+
if p_id:
|
170
|
+
self.active_connections[p_id] = websocket
|
171
|
+
|
172
|
+
# Process the received message.
|
173
|
+
await self.on_message_callback(msg)
|
174
|
+
except websockets.exceptions.ConnectionClosed:
|
175
|
+
logger.error(f"[WsClient] Connection with {peer_id} closed")
|
176
|
+
finally:
|
177
|
+
if peer_id in self.active_connections:
|
178
|
+
del self.active_connections[peer_id]
|
179
|
+
if self.on_peer_disconnected:
|
180
|
+
await self.on_peer_disconnected(peer_id)
|
181
|
+
|
182
|
+
async def send_message(self, peer_id: str, msg: Dict[str, Any]) -> None:
|
183
|
+
"""
|
184
|
+
Send a message to a specific peer via an active WebSocket connection.
|
185
|
+
|
186
|
+
Args:
|
187
|
+
peer_id (str): Unique identifier of the peer.
|
188
|
+
msg (Dict[str, Any]): The message payload as a dictionary.
|
189
|
+
"""
|
190
|
+
websocket = self.active_connections.get(peer_id)
|
191
|
+
if websocket:
|
192
|
+
try:
|
193
|
+
await websocket.send(json.dumps(msg))
|
194
|
+
except Exception as e:
|
195
|
+
logger.error(f"[WsConnector] Error sending message to {peer_id}: {e}")
|
196
|
+
else:
|
197
|
+
logger.info(f"[WsConnector] Message sent to {peer_id}")
|
198
|
+
else:
|
199
|
+
logger.info(f"[WsConnector] No active connection with: {peer_id}")
|
200
|
+
|
201
|
+
|
202
|
+
async def disconnect_from_peer(self, peer_id: str) -> None:
|
203
|
+
"""
|
204
|
+
Close websocket connection
|
205
|
+
|
206
|
+
Args:
|
207
|
+
peer_id (str): Unique identifier of the lost peer.
|
208
|
+
"""
|
209
|
+
try:
|
210
|
+
await self.active_connections[peer_id].close()
|
211
|
+
logger.info(f"[WsConnector] Closed WebSocket connection: {peer_id=}")
|
212
|
+
except Exception as e:
|
213
|
+
logger.error(f"[WsConnector] Error while disconnecting from {peer_id=}: {e}")
|
File without changes
|