@@ -53,7 +53,7 @@ def __init__(
53
53
self .broadcast_interval = broadcast_interval
54
54
self .discovery_timeout = discovery_timeout
55
55
self .device_capabilities = device_capabilities
56
- self .known_peers : Dict [str , Tuple [PeerHandle , float , float ]] = {}
56
+ self .known_peers : Dict [str , Tuple [PeerHandle , float , float , int ]] = {}
57
57
self .broadcast_task = None
58
58
self .listen_task = None
59
59
self .cleanup_task = None
@@ -76,24 +76,25 @@ async def discover_peers(self, wait_for_peers: int = 0) -> List[PeerHandle]:
76
76
while len (self .known_peers ) < wait_for_peers :
77
77
if DEBUG_DISCOVERY >= 2 : print (f"Current peers: { len (self .known_peers )} /{ wait_for_peers } . Waiting for more peers..." )
78
78
await asyncio .sleep (0.1 )
79
- return [peer_handle for peer_handle , _ , _ in self .known_peers .values ()]
79
+ return [peer_handle for peer_handle , _ , _ , _ in self .known_peers .values ()]
80
80
81
81
async def task_broadcast_presence (self ):
82
- message = json .dumps ({
83
- "type" : "discovery" ,
84
- "node_id" : self .node_id ,
85
- "grpc_port" : self .node_port ,
86
- "device_capabilities" : self .device_capabilities .to_dict (),
87
- })
88
-
89
82
if DEBUG_DISCOVERY >= 2 :
90
83
print ("Starting task_broadcast_presence..." )
91
- print (f"\n Broadcast message: { message } " )
92
84
93
85
while True :
94
86
# Explicitly broadcasting on all assigned ips since broadcasting on `0.0.0.0` on MacOS does not broadcast over
95
87
# the Thunderbolt bridge when other connection modalities exist such as WiFi or Ethernet
96
88
for addr in get_all_ip_addresses ():
89
+ message = json .dumps ({
90
+ "type" : "discovery" ,
91
+ "node_id" : self .node_id ,
92
+ "grpc_port" : self .node_port ,
93
+ "device_capabilities" : self .device_capabilities .to_dict (),
94
+ "priority" : 1 , # For now, every interface has the same priority. We can make this better by prioriting interfaces based on bandwidth, latency, and jitter e.g. prioritise Thunderbolt over WiFi.
95
+ })
96
+ if DEBUG_DISCOVERY >= 3 : print (f"Broadcasting presence at ({ addr } ): { message } " )
97
+
97
98
transport = None
98
99
try :
99
100
transport , _ = await asyncio .get_event_loop ().create_datagram_endpoint (
@@ -138,21 +139,27 @@ async def on_listen_message(self, data, addr):
138
139
peer_id = message ["node_id" ]
139
140
peer_host = addr [0 ]
140
141
peer_port = message ["grpc_port" ]
142
+ peer_prio = message ["priority" ]
141
143
device_capabilities = DeviceCapabilities (** message ["device_capabilities" ])
142
144
143
145
if peer_id not in self .known_peers or self .known_peers [peer_id ][0 ].addr () != f"{ peer_host } :{ peer_port } " :
146
+ if peer_id in self .known_peers :
147
+ existing_peer_prio = self .known_peers [peer_id ][3 ]
148
+ if existing_peer_prio >= peer_prio :
149
+ if DEBUG >= 1 : print (f"Ignoring peer { peer_id } at { peer_host } :{ peer_port } with priority { peer_prio } because we already know about a peer with higher or equal priority: { existing_peer_prio } " )
150
+ return
144
151
new_peer_handle = self .create_peer_handle (peer_id , f"{ peer_host } :{ peer_port } " , device_capabilities )
145
152
if not await new_peer_handle .health_check ():
146
153
if DEBUG >= 1 : print (f"Peer { peer_id } at { peer_host } :{ peer_port } is not healthy. Skipping." )
147
154
return
148
155
if DEBUG >= 1 : print (f"Adding { peer_id = } at { peer_host } :{ peer_port } . Replace existing peer_id: { peer_id in self .known_peers } " )
149
- self .known_peers [peer_id ] = (new_peer_handle , time .time (), time .time ())
156
+ self .known_peers [peer_id ] = (new_peer_handle , time .time (), time .time (), peer_prio )
150
157
else :
151
158
if not await self .known_peers [peer_id ][0 ].health_check ():
152
159
if DEBUG >= 1 : print (f"Peer { peer_id } at { peer_host } :{ peer_port } is not healthy. Removing." )
153
160
if peer_id in self .known_peers : del self .known_peers [peer_id ]
154
161
return
155
- self .known_peers [peer_id ] = (self .known_peers [peer_id ][0 ], self .known_peers [peer_id ][1 ], time .time ())
162
+ self .known_peers [peer_id ] = (self .known_peers [peer_id ][0 ], self .known_peers [peer_id ][1 ], time .time (), peer_prio )
156
163
157
164
async def task_listen_for_peers (self ):
158
165
await asyncio .get_event_loop ().create_datagram_endpoint (lambda : ListenProtocol (self .on_listen_message ),
@@ -164,13 +171,13 @@ async def task_cleanup_peers(self):
164
171
try :
165
172
current_time = time .time ()
166
173
peers_to_remove = []
167
- for peer_id , (peer_handle , connected_at , last_seen ) in self .known_peers .items ():
174
+ for peer_id , (peer_handle , connected_at , last_seen , prio ) in self .known_peers .items ():
168
175
if (not await peer_handle .is_connected () and current_time - connected_at > self .discovery_timeout ) or \
169
176
(current_time - last_seen > self .discovery_timeout ) or \
170
177
(not await peer_handle .health_check ()):
171
178
peers_to_remove .append (peer_id )
172
179
173
- if DEBUG_DISCOVERY >= 2 : print ("Peer statuses:" , {peer_handle .id (): f"is_connected={ await peer_handle .is_connected ()} , health_check={ await peer_handle .health_check ()} , { connected_at = } , { last_seen = } " for peer_handle , connected_at , last_seen in self .known_peers .values ()})
180
+ if DEBUG_DISCOVERY >= 2 : print ("Peer statuses:" , {peer_handle .id (): f"is_connected={ await peer_handle .is_connected ()} , health_check={ await peer_handle .health_check ()} , { connected_at = } , { last_seen = } , { prio = } " for peer_handle , connected_at , last_seen , prio in self .known_peers .values ()})
174
181
175
182
for peer_id in peers_to_remove :
176
183
if peer_id in self .known_peers : del self .known_peers [peer_id ]
0 commit comments