flwr-nightly 1.15.0.dev20250108__py3-none-any.whl → 1.15.0.dev20250109__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.
- flwr/client/grpc_rere_client/client_interceptor.py +6 -0
- flwr/client/grpc_rere_client/grpc_adapter.py +16 -0
- flwr/proto/fleet_pb2.py +40 -27
- flwr/proto/fleet_pb2.pyi +84 -0
- flwr/proto/fleet_pb2_grpc.py +66 -0
- flwr/proto/fleet_pb2_grpc.pyi +20 -0
- flwr/server/superlink/driver/serverappio_servicer.py +22 -8
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +16 -0
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +2 -1
- flwr/server/superlink/linkstate/in_memory_linkstate.py +26 -22
- flwr/server/superlink/linkstate/linkstate.py +10 -4
- flwr/server/superlink/linkstate/sqlite_linkstate.py +42 -20
- {flwr_nightly-1.15.0.dev20250108.dist-info → flwr_nightly-1.15.0.dev20250109.dist-info}/METADATA +2 -2
- {flwr_nightly-1.15.0.dev20250108.dist-info → flwr_nightly-1.15.0.dev20250109.dist-info}/RECORD +17 -17
- {flwr_nightly-1.15.0.dev20250108.dist-info → flwr_nightly-1.15.0.dev20250109.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.15.0.dev20250108.dist-info → flwr_nightly-1.15.0.dev20250109.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.15.0.dev20250108.dist-info → flwr_nightly-1.15.0.dev20250109.dist-info}/entry_points.txt +0 -0
@@ -36,7 +36,9 @@ from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
36
36
|
CreateNodeRequest,
|
37
37
|
DeleteNodeRequest,
|
38
38
|
PingRequest,
|
39
|
+
PullMessagesRequest,
|
39
40
|
PullTaskInsRequest,
|
41
|
+
PushMessagesRequest,
|
40
42
|
PushTaskResRequest,
|
41
43
|
)
|
42
44
|
from flwr.proto.run_pb2 import GetRunRequest # pylint: disable=E0611
|
@@ -52,6 +54,8 @@ Request = Union[
|
|
52
54
|
GetRunRequest,
|
53
55
|
PingRequest,
|
54
56
|
GetFabRequest,
|
57
|
+
PullMessagesRequest,
|
58
|
+
PushMessagesRequest,
|
55
59
|
]
|
56
60
|
|
57
61
|
|
@@ -129,6 +133,8 @@ class AuthenticateClientInterceptor(grpc.UnaryUnaryClientInterceptor): # type:
|
|
129
133
|
GetRunRequest,
|
130
134
|
PingRequest,
|
131
135
|
GetFabRequest,
|
136
|
+
PullMessagesRequest,
|
137
|
+
PushMessagesRequest,
|
132
138
|
),
|
133
139
|
):
|
134
140
|
if self.shared_secret is None:
|
@@ -40,8 +40,12 @@ from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
40
40
|
DeleteNodeResponse,
|
41
41
|
PingRequest,
|
42
42
|
PingResponse,
|
43
|
+
PullMessagesRequest,
|
44
|
+
PullMessagesResponse,
|
43
45
|
PullTaskInsRequest,
|
44
46
|
PullTaskInsResponse,
|
47
|
+
PushMessagesRequest,
|
48
|
+
PushMessagesResponse,
|
45
49
|
PushTaskResRequest,
|
46
50
|
PushTaskResResponse,
|
47
51
|
)
|
@@ -132,12 +136,24 @@ class GrpcAdapter:
|
|
132
136
|
"""."""
|
133
137
|
return self._send_and_receive(request, PullTaskInsResponse, **kwargs)
|
134
138
|
|
139
|
+
def PullMessages( # pylint: disable=C0103
|
140
|
+
self, request: PullMessagesRequest, **kwargs: Any
|
141
|
+
) -> PullMessagesResponse:
|
142
|
+
"""."""
|
143
|
+
return self._send_and_receive(request, PullMessagesResponse, **kwargs)
|
144
|
+
|
135
145
|
def PushTaskRes( # pylint: disable=C0103
|
136
146
|
self, request: PushTaskResRequest, **kwargs: Any
|
137
147
|
) -> PushTaskResResponse:
|
138
148
|
"""."""
|
139
149
|
return self._send_and_receive(request, PushTaskResResponse, **kwargs)
|
140
150
|
|
151
|
+
def PushMessages( # pylint: disable=C0103
|
152
|
+
self, request: PushMessagesRequest, **kwargs: Any
|
153
|
+
) -> PushMessagesResponse:
|
154
|
+
"""."""
|
155
|
+
return self._send_and_receive(request, PushMessagesResponse, **kwargs)
|
156
|
+
|
141
157
|
def GetRun( # pylint: disable=C0103
|
142
158
|
self, request: GetRunRequest, **kwargs: Any
|
143
159
|
) -> GetRunResponse:
|
flwr/proto/fleet_pb2.py
CHANGED
@@ -16,9 +16,10 @@ from flwr.proto import node_pb2 as flwr_dot_proto_dot_node__pb2
|
|
16
16
|
from flwr.proto import task_pb2 as flwr_dot_proto_dot_task__pb2
|
17
17
|
from flwr.proto import run_pb2 as flwr_dot_proto_dot_run__pb2
|
18
18
|
from flwr.proto import fab_pb2 as flwr_dot_proto_dot_fab__pb2
|
19
|
+
from flwr.proto import message_pb2 as flwr_dot_proto_dot_message__pb2
|
19
20
|
|
20
21
|
|
21
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/fleet.proto\x12\nflwr.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x15\x66lwr/proto/task.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\"*\n\x11\x43reateNodeRequest\x12\x15\n\rping_interval\x18\x01 \x01(\x01\"4\n\x12\x43reateNodeResponse\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"3\n\x11\x44\x65leteNodeRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"\x14\n\x12\x44\x65leteNodeResponse\"D\n\x0bPingRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x15\n\rping_interval\x18\x02 \x01(\x01\"\x1f\n\x0cPingResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"F\n\x12PullTaskInsRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x10\n\x08task_ids\x18\x02 \x03(\t\"k\n\x13PullTaskInsResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12*\n\rtask_ins_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.TaskIns\"`\n\x12PushTaskResRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12*\n\rtask_res_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.TaskRes\"\xae\x01\n\x13PushTaskResResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12=\n\x07results\x18\x02 \x03(\x0b\x32,.flwr.proto.PushTaskResResponse.ResultsEntry\x1a.\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\"\x1e\n\tReconnect\x12\x11\n\treconnect\x18\x01 \x01(\x04\x32\
|
22
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/fleet.proto\x12\nflwr.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x15\x66lwr/proto/task.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x18\x66lwr/proto/message.proto\"*\n\x11\x43reateNodeRequest\x12\x15\n\rping_interval\x18\x01 \x01(\x01\"4\n\x12\x43reateNodeResponse\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"3\n\x11\x44\x65leteNodeRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"\x14\n\x12\x44\x65leteNodeResponse\"D\n\x0bPingRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x15\n\rping_interval\x18\x02 \x01(\x01\"\x1f\n\x0cPingResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"F\n\x12PullTaskInsRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x10\n\x08task_ids\x18\x02 \x03(\t\"k\n\x13PullTaskInsResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12*\n\rtask_ins_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.TaskIns\"`\n\x12PushTaskResRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12*\n\rtask_res_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.TaskRes\"\xae\x01\n\x13PushTaskResResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12=\n\x07results\x18\x02 \x03(\x0b\x32,.flwr.proto.PushTaskResResponse.ResultsEntry\x1a.\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\"J\n\x13PullMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x13\n\x0bmessage_ids\x18\x02 \x03(\t\"l\n\x14PullMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\"a\n\x13PushMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\"\xb0\x01\n\x14PushMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12>\n\x07results\x18\x02 \x03(\x0b\x32-.flwr.proto.PushMessagesResponse.ResultsEntry\x1a.\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\"\x1e\n\tReconnect\x12\x11\n\treconnect\x18\x01 \x01(\x04\x32\xb6\x05\n\x05\x46leet\x12M\n\nCreateNode\x12\x1d.flwr.proto.CreateNodeRequest\x1a\x1e.flwr.proto.CreateNodeResponse\"\x00\x12M\n\nDeleteNode\x12\x1d.flwr.proto.DeleteNodeRequest\x1a\x1e.flwr.proto.DeleteNodeResponse\"\x00\x12;\n\x04Ping\x12\x17.flwr.proto.PingRequest\x1a\x18.flwr.proto.PingResponse\"\x00\x12P\n\x0bPullTaskIns\x12\x1e.flwr.proto.PullTaskInsRequest\x1a\x1f.flwr.proto.PullTaskInsResponse\"\x00\x12S\n\x0cPullMessages\x12\x1f.flwr.proto.PullMessagesRequest\x1a .flwr.proto.PullMessagesResponse\"\x00\x12P\n\x0bPushTaskRes\x12\x1e.flwr.proto.PushTaskResRequest\x1a\x1f.flwr.proto.PushTaskResResponse\"\x00\x12S\n\x0cPushMessages\x12\x1f.flwr.proto.PushMessagesRequest\x1a .flwr.proto.PushMessagesResponse\"\x00\x12\x41\n\x06GetRun\x12\x19.flwr.proto.GetRunRequest\x1a\x1a.flwr.proto.GetRunResponse\"\x00\x12\x41\n\x06GetFab\x12\x19.flwr.proto.GetFabRequest\x1a\x1a.flwr.proto.GetFabResponse\"\x00\x62\x06proto3')
|
22
23
|
|
23
24
|
_globals = globals()
|
24
25
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
@@ -27,30 +28,42 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
27
28
|
DESCRIPTOR._options = None
|
28
29
|
_globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._options = None
|
29
30
|
_globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._serialized_options = b'8\001'
|
30
|
-
_globals['
|
31
|
-
_globals['
|
32
|
-
_globals['
|
33
|
-
_globals['
|
34
|
-
_globals['
|
35
|
-
_globals['
|
36
|
-
_globals['
|
37
|
-
_globals['
|
38
|
-
_globals['
|
39
|
-
_globals['
|
40
|
-
_globals['
|
41
|
-
_globals['
|
42
|
-
_globals['
|
43
|
-
_globals['
|
44
|
-
_globals['
|
45
|
-
_globals['
|
46
|
-
_globals['
|
47
|
-
_globals['
|
48
|
-
_globals['
|
49
|
-
_globals['
|
50
|
-
_globals['
|
51
|
-
_globals['
|
52
|
-
_globals['
|
53
|
-
_globals['
|
54
|
-
_globals['
|
55
|
-
_globals['
|
31
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._options = None
|
32
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_options = b'8\001'
|
33
|
+
_globals['_CREATENODEREQUEST']._serialized_start=154
|
34
|
+
_globals['_CREATENODEREQUEST']._serialized_end=196
|
35
|
+
_globals['_CREATENODERESPONSE']._serialized_start=198
|
36
|
+
_globals['_CREATENODERESPONSE']._serialized_end=250
|
37
|
+
_globals['_DELETENODEREQUEST']._serialized_start=252
|
38
|
+
_globals['_DELETENODEREQUEST']._serialized_end=303
|
39
|
+
_globals['_DELETENODERESPONSE']._serialized_start=305
|
40
|
+
_globals['_DELETENODERESPONSE']._serialized_end=325
|
41
|
+
_globals['_PINGREQUEST']._serialized_start=327
|
42
|
+
_globals['_PINGREQUEST']._serialized_end=395
|
43
|
+
_globals['_PINGRESPONSE']._serialized_start=397
|
44
|
+
_globals['_PINGRESPONSE']._serialized_end=428
|
45
|
+
_globals['_PULLTASKINSREQUEST']._serialized_start=430
|
46
|
+
_globals['_PULLTASKINSREQUEST']._serialized_end=500
|
47
|
+
_globals['_PULLTASKINSRESPONSE']._serialized_start=502
|
48
|
+
_globals['_PULLTASKINSRESPONSE']._serialized_end=609
|
49
|
+
_globals['_PUSHTASKRESREQUEST']._serialized_start=611
|
50
|
+
_globals['_PUSHTASKRESREQUEST']._serialized_end=707
|
51
|
+
_globals['_PUSHTASKRESRESPONSE']._serialized_start=710
|
52
|
+
_globals['_PUSHTASKRESRESPONSE']._serialized_end=884
|
53
|
+
_globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._serialized_start=838
|
54
|
+
_globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._serialized_end=884
|
55
|
+
_globals['_PULLMESSAGESREQUEST']._serialized_start=886
|
56
|
+
_globals['_PULLMESSAGESREQUEST']._serialized_end=960
|
57
|
+
_globals['_PULLMESSAGESRESPONSE']._serialized_start=962
|
58
|
+
_globals['_PULLMESSAGESRESPONSE']._serialized_end=1070
|
59
|
+
_globals['_PUSHMESSAGESREQUEST']._serialized_start=1072
|
60
|
+
_globals['_PUSHMESSAGESREQUEST']._serialized_end=1169
|
61
|
+
_globals['_PUSHMESSAGESRESPONSE']._serialized_start=1172
|
62
|
+
_globals['_PUSHMESSAGESRESPONSE']._serialized_end=1348
|
63
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_start=838
|
64
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_end=884
|
65
|
+
_globals['_RECONNECT']._serialized_start=1350
|
66
|
+
_globals['_RECONNECT']._serialized_end=1380
|
67
|
+
_globals['_FLEET']._serialized_start=1383
|
68
|
+
_globals['_FLEET']._serialized_end=2077
|
56
69
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/fleet_pb2.pyi
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
isort:skip_file
|
4
4
|
"""
|
5
5
|
import builtins
|
6
|
+
import flwr.proto.message_pb2
|
6
7
|
import flwr.proto.node_pb2
|
7
8
|
import flwr.proto.task_pb2
|
8
9
|
import google.protobuf.descriptor
|
@@ -169,6 +170,89 @@ class PushTaskResResponse(google.protobuf.message.Message):
|
|
169
170
|
def ClearField(self, field_name: typing_extensions.Literal["reconnect",b"reconnect","results",b"results"]) -> None: ...
|
170
171
|
global___PushTaskResResponse = PushTaskResResponse
|
171
172
|
|
173
|
+
class PullMessagesRequest(google.protobuf.message.Message):
|
174
|
+
"""PullMessages messages"""
|
175
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
176
|
+
NODE_FIELD_NUMBER: builtins.int
|
177
|
+
MESSAGE_IDS_FIELD_NUMBER: builtins.int
|
178
|
+
@property
|
179
|
+
def node(self) -> flwr.proto.node_pb2.Node: ...
|
180
|
+
@property
|
181
|
+
def message_ids(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[typing.Text]: ...
|
182
|
+
def __init__(self,
|
183
|
+
*,
|
184
|
+
node: typing.Optional[flwr.proto.node_pb2.Node] = ...,
|
185
|
+
message_ids: typing.Optional[typing.Iterable[typing.Text]] = ...,
|
186
|
+
) -> None: ...
|
187
|
+
def HasField(self, field_name: typing_extensions.Literal["node",b"node"]) -> builtins.bool: ...
|
188
|
+
def ClearField(self, field_name: typing_extensions.Literal["message_ids",b"message_ids","node",b"node"]) -> None: ...
|
189
|
+
global___PullMessagesRequest = PullMessagesRequest
|
190
|
+
|
191
|
+
class PullMessagesResponse(google.protobuf.message.Message):
|
192
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
193
|
+
RECONNECT_FIELD_NUMBER: builtins.int
|
194
|
+
MESSAGES_LIST_FIELD_NUMBER: builtins.int
|
195
|
+
@property
|
196
|
+
def reconnect(self) -> global___Reconnect: ...
|
197
|
+
@property
|
198
|
+
def messages_list(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[flwr.proto.message_pb2.Message]: ...
|
199
|
+
def __init__(self,
|
200
|
+
*,
|
201
|
+
reconnect: typing.Optional[global___Reconnect] = ...,
|
202
|
+
messages_list: typing.Optional[typing.Iterable[flwr.proto.message_pb2.Message]] = ...,
|
203
|
+
) -> None: ...
|
204
|
+
def HasField(self, field_name: typing_extensions.Literal["reconnect",b"reconnect"]) -> builtins.bool: ...
|
205
|
+
def ClearField(self, field_name: typing_extensions.Literal["messages_list",b"messages_list","reconnect",b"reconnect"]) -> None: ...
|
206
|
+
global___PullMessagesResponse = PullMessagesResponse
|
207
|
+
|
208
|
+
class PushMessagesRequest(google.protobuf.message.Message):
|
209
|
+
"""PushMessages messages"""
|
210
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
211
|
+
NODE_FIELD_NUMBER: builtins.int
|
212
|
+
MESSAGES_LIST_FIELD_NUMBER: builtins.int
|
213
|
+
@property
|
214
|
+
def node(self) -> flwr.proto.node_pb2.Node: ...
|
215
|
+
@property
|
216
|
+
def messages_list(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[flwr.proto.message_pb2.Message]: ...
|
217
|
+
def __init__(self,
|
218
|
+
*,
|
219
|
+
node: typing.Optional[flwr.proto.node_pb2.Node] = ...,
|
220
|
+
messages_list: typing.Optional[typing.Iterable[flwr.proto.message_pb2.Message]] = ...,
|
221
|
+
) -> None: ...
|
222
|
+
def HasField(self, field_name: typing_extensions.Literal["node",b"node"]) -> builtins.bool: ...
|
223
|
+
def ClearField(self, field_name: typing_extensions.Literal["messages_list",b"messages_list","node",b"node"]) -> None: ...
|
224
|
+
global___PushMessagesRequest = PushMessagesRequest
|
225
|
+
|
226
|
+
class PushMessagesResponse(google.protobuf.message.Message):
|
227
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
228
|
+
class ResultsEntry(google.protobuf.message.Message):
|
229
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
230
|
+
KEY_FIELD_NUMBER: builtins.int
|
231
|
+
VALUE_FIELD_NUMBER: builtins.int
|
232
|
+
key: typing.Text
|
233
|
+
value: builtins.int
|
234
|
+
def __init__(self,
|
235
|
+
*,
|
236
|
+
key: typing.Text = ...,
|
237
|
+
value: builtins.int = ...,
|
238
|
+
) -> None: ...
|
239
|
+
def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ...
|
240
|
+
|
241
|
+
RECONNECT_FIELD_NUMBER: builtins.int
|
242
|
+
RESULTS_FIELD_NUMBER: builtins.int
|
243
|
+
@property
|
244
|
+
def reconnect(self) -> global___Reconnect: ...
|
245
|
+
@property
|
246
|
+
def results(self) -> google.protobuf.internal.containers.ScalarMap[typing.Text, builtins.int]: ...
|
247
|
+
def __init__(self,
|
248
|
+
*,
|
249
|
+
reconnect: typing.Optional[global___Reconnect] = ...,
|
250
|
+
results: typing.Optional[typing.Mapping[typing.Text, builtins.int]] = ...,
|
251
|
+
) -> None: ...
|
252
|
+
def HasField(self, field_name: typing_extensions.Literal["reconnect",b"reconnect"]) -> builtins.bool: ...
|
253
|
+
def ClearField(self, field_name: typing_extensions.Literal["reconnect",b"reconnect","results",b"results"]) -> None: ...
|
254
|
+
global___PushMessagesResponse = PushMessagesResponse
|
255
|
+
|
172
256
|
class Reconnect(google.protobuf.message.Message):
|
173
257
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
174
258
|
RECONNECT_FIELD_NUMBER: builtins.int
|
flwr/proto/fleet_pb2_grpc.py
CHANGED
@@ -36,11 +36,21 @@ class FleetStub(object):
|
|
36
36
|
request_serializer=flwr_dot_proto_dot_fleet__pb2.PullTaskInsRequest.SerializeToString,
|
37
37
|
response_deserializer=flwr_dot_proto_dot_fleet__pb2.PullTaskInsResponse.FromString,
|
38
38
|
)
|
39
|
+
self.PullMessages = channel.unary_unary(
|
40
|
+
'/flwr.proto.Fleet/PullMessages',
|
41
|
+
request_serializer=flwr_dot_proto_dot_fleet__pb2.PullMessagesRequest.SerializeToString,
|
42
|
+
response_deserializer=flwr_dot_proto_dot_fleet__pb2.PullMessagesResponse.FromString,
|
43
|
+
)
|
39
44
|
self.PushTaskRes = channel.unary_unary(
|
40
45
|
'/flwr.proto.Fleet/PushTaskRes',
|
41
46
|
request_serializer=flwr_dot_proto_dot_fleet__pb2.PushTaskResRequest.SerializeToString,
|
42
47
|
response_deserializer=flwr_dot_proto_dot_fleet__pb2.PushTaskResResponse.FromString,
|
43
48
|
)
|
49
|
+
self.PushMessages = channel.unary_unary(
|
50
|
+
'/flwr.proto.Fleet/PushMessages',
|
51
|
+
request_serializer=flwr_dot_proto_dot_fleet__pb2.PushMessagesRequest.SerializeToString,
|
52
|
+
response_deserializer=flwr_dot_proto_dot_fleet__pb2.PushMessagesResponse.FromString,
|
53
|
+
)
|
44
54
|
self.GetRun = channel.unary_unary(
|
45
55
|
'/flwr.proto.Fleet/GetRun',
|
46
56
|
request_serializer=flwr_dot_proto_dot_run__pb2.GetRunRequest.SerializeToString,
|
@@ -83,6 +93,12 @@ class FleetServicer(object):
|
|
83
93
|
context.set_details('Method not implemented!')
|
84
94
|
raise NotImplementedError('Method not implemented!')
|
85
95
|
|
96
|
+
def PullMessages(self, request, context):
|
97
|
+
"""Missing associated documentation comment in .proto file."""
|
98
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
99
|
+
context.set_details('Method not implemented!')
|
100
|
+
raise NotImplementedError('Method not implemented!')
|
101
|
+
|
86
102
|
def PushTaskRes(self, request, context):
|
87
103
|
"""Complete one or more tasks, if possible
|
88
104
|
|
@@ -92,6 +108,12 @@ class FleetServicer(object):
|
|
92
108
|
context.set_details('Method not implemented!')
|
93
109
|
raise NotImplementedError('Method not implemented!')
|
94
110
|
|
111
|
+
def PushMessages(self, request, context):
|
112
|
+
"""Missing associated documentation comment in .proto file."""
|
113
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
114
|
+
context.set_details('Method not implemented!')
|
115
|
+
raise NotImplementedError('Method not implemented!')
|
116
|
+
|
95
117
|
def GetRun(self, request, context):
|
96
118
|
"""Missing associated documentation comment in .proto file."""
|
97
119
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
@@ -128,11 +150,21 @@ def add_FleetServicer_to_server(servicer, server):
|
|
128
150
|
request_deserializer=flwr_dot_proto_dot_fleet__pb2.PullTaskInsRequest.FromString,
|
129
151
|
response_serializer=flwr_dot_proto_dot_fleet__pb2.PullTaskInsResponse.SerializeToString,
|
130
152
|
),
|
153
|
+
'PullMessages': grpc.unary_unary_rpc_method_handler(
|
154
|
+
servicer.PullMessages,
|
155
|
+
request_deserializer=flwr_dot_proto_dot_fleet__pb2.PullMessagesRequest.FromString,
|
156
|
+
response_serializer=flwr_dot_proto_dot_fleet__pb2.PullMessagesResponse.SerializeToString,
|
157
|
+
),
|
131
158
|
'PushTaskRes': grpc.unary_unary_rpc_method_handler(
|
132
159
|
servicer.PushTaskRes,
|
133
160
|
request_deserializer=flwr_dot_proto_dot_fleet__pb2.PushTaskResRequest.FromString,
|
134
161
|
response_serializer=flwr_dot_proto_dot_fleet__pb2.PushTaskResResponse.SerializeToString,
|
135
162
|
),
|
163
|
+
'PushMessages': grpc.unary_unary_rpc_method_handler(
|
164
|
+
servicer.PushMessages,
|
165
|
+
request_deserializer=flwr_dot_proto_dot_fleet__pb2.PushMessagesRequest.FromString,
|
166
|
+
response_serializer=flwr_dot_proto_dot_fleet__pb2.PushMessagesResponse.SerializeToString,
|
167
|
+
),
|
136
168
|
'GetRun': grpc.unary_unary_rpc_method_handler(
|
137
169
|
servicer.GetRun,
|
138
170
|
request_deserializer=flwr_dot_proto_dot_run__pb2.GetRunRequest.FromString,
|
@@ -221,6 +253,23 @@ class Fleet(object):
|
|
221
253
|
options, channel_credentials,
|
222
254
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
223
255
|
|
256
|
+
@staticmethod
|
257
|
+
def PullMessages(request,
|
258
|
+
target,
|
259
|
+
options=(),
|
260
|
+
channel_credentials=None,
|
261
|
+
call_credentials=None,
|
262
|
+
insecure=False,
|
263
|
+
compression=None,
|
264
|
+
wait_for_ready=None,
|
265
|
+
timeout=None,
|
266
|
+
metadata=None):
|
267
|
+
return grpc.experimental.unary_unary(request, target, '/flwr.proto.Fleet/PullMessages',
|
268
|
+
flwr_dot_proto_dot_fleet__pb2.PullMessagesRequest.SerializeToString,
|
269
|
+
flwr_dot_proto_dot_fleet__pb2.PullMessagesResponse.FromString,
|
270
|
+
options, channel_credentials,
|
271
|
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
272
|
+
|
224
273
|
@staticmethod
|
225
274
|
def PushTaskRes(request,
|
226
275
|
target,
|
@@ -238,6 +287,23 @@ class Fleet(object):
|
|
238
287
|
options, channel_credentials,
|
239
288
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
240
289
|
|
290
|
+
@staticmethod
|
291
|
+
def PushMessages(request,
|
292
|
+
target,
|
293
|
+
options=(),
|
294
|
+
channel_credentials=None,
|
295
|
+
call_credentials=None,
|
296
|
+
insecure=False,
|
297
|
+
compression=None,
|
298
|
+
wait_for_ready=None,
|
299
|
+
timeout=None,
|
300
|
+
metadata=None):
|
301
|
+
return grpc.experimental.unary_unary(request, target, '/flwr.proto.Fleet/PushMessages',
|
302
|
+
flwr_dot_proto_dot_fleet__pb2.PushMessagesRequest.SerializeToString,
|
303
|
+
flwr_dot_proto_dot_fleet__pb2.PushMessagesResponse.FromString,
|
304
|
+
options, channel_credentials,
|
305
|
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
306
|
+
|
241
307
|
@staticmethod
|
242
308
|
def GetRun(request,
|
243
309
|
target,
|
flwr/proto/fleet_pb2_grpc.pyi
CHANGED
@@ -30,6 +30,10 @@ class FleetStub:
|
|
30
30
|
HTTP API path: /api/v1/fleet/pull-task-ins
|
31
31
|
"""
|
32
32
|
|
33
|
+
PullMessages: grpc.UnaryUnaryMultiCallable[
|
34
|
+
flwr.proto.fleet_pb2.PullMessagesRequest,
|
35
|
+
flwr.proto.fleet_pb2.PullMessagesResponse]
|
36
|
+
|
33
37
|
PushTaskRes: grpc.UnaryUnaryMultiCallable[
|
34
38
|
flwr.proto.fleet_pb2.PushTaskResRequest,
|
35
39
|
flwr.proto.fleet_pb2.PushTaskResResponse]
|
@@ -38,6 +42,10 @@ class FleetStub:
|
|
38
42
|
HTTP API path: /api/v1/fleet/push-task-res
|
39
43
|
"""
|
40
44
|
|
45
|
+
PushMessages: grpc.UnaryUnaryMultiCallable[
|
46
|
+
flwr.proto.fleet_pb2.PushMessagesRequest,
|
47
|
+
flwr.proto.fleet_pb2.PushMessagesResponse]
|
48
|
+
|
41
49
|
GetRun: grpc.UnaryUnaryMultiCallable[
|
42
50
|
flwr.proto.run_pb2.GetRunRequest,
|
43
51
|
flwr.proto.run_pb2.GetRunResponse]
|
@@ -78,6 +86,12 @@ class FleetServicer(metaclass=abc.ABCMeta):
|
|
78
86
|
"""
|
79
87
|
pass
|
80
88
|
|
89
|
+
@abc.abstractmethod
|
90
|
+
def PullMessages(self,
|
91
|
+
request: flwr.proto.fleet_pb2.PullMessagesRequest,
|
92
|
+
context: grpc.ServicerContext,
|
93
|
+
) -> flwr.proto.fleet_pb2.PullMessagesResponse: ...
|
94
|
+
|
81
95
|
@abc.abstractmethod
|
82
96
|
def PushTaskRes(self,
|
83
97
|
request: flwr.proto.fleet_pb2.PushTaskResRequest,
|
@@ -89,6 +103,12 @@ class FleetServicer(metaclass=abc.ABCMeta):
|
|
89
103
|
"""
|
90
104
|
pass
|
91
105
|
|
106
|
+
@abc.abstractmethod
|
107
|
+
def PushMessages(self,
|
108
|
+
request: flwr.proto.fleet_pb2.PushMessagesRequest,
|
109
|
+
context: grpc.ServicerContext,
|
110
|
+
) -> flwr.proto.fleet_pb2.PushMessagesResponse: ...
|
111
|
+
|
92
112
|
@abc.abstractmethod
|
93
113
|
def GetRun(self,
|
94
114
|
request: flwr.proto.run_pb2.GetRunRequest,
|
@@ -118,8 +118,9 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
|
|
118
118
|
ffs: Ffs = self.ffs_factory.ffs()
|
119
119
|
fab_hash = ffs.put(fab.content, {})
|
120
120
|
_raise_if(
|
121
|
-
fab_hash != fab.hash_str,
|
122
|
-
|
121
|
+
validation_error=fab_hash != fab.hash_str,
|
122
|
+
request_name="CreateRun",
|
123
|
+
detail=f"FAB ({fab.hash_str}) hash from request doesn't match contents",
|
123
124
|
)
|
124
125
|
else:
|
125
126
|
fab_hash = ""
|
@@ -155,12 +156,22 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
|
|
155
156
|
task_ins.task.pushed_at = pushed_at
|
156
157
|
|
157
158
|
# Validate request
|
158
|
-
_raise_if(
|
159
|
+
_raise_if(
|
160
|
+
validation_error=len(request.task_ins_list) == 0,
|
161
|
+
request_name="PushTaskIns",
|
162
|
+
detail="`task_ins_list` must not be empty",
|
163
|
+
)
|
159
164
|
for task_ins in request.task_ins_list:
|
160
165
|
validation_errors = validate_task_ins_or_res(task_ins)
|
161
|
-
_raise_if(bool(validation_errors), ", ".join(validation_errors))
|
162
166
|
_raise_if(
|
163
|
-
|
167
|
+
validation_error=bool(validation_errors),
|
168
|
+
request_name="PushTaskIns",
|
169
|
+
detail=", ".join(validation_errors),
|
170
|
+
)
|
171
|
+
_raise_if(
|
172
|
+
validation_error=request.run_id != task_ins.run_id,
|
173
|
+
request_name="PushTaskIns",
|
174
|
+
detail="`task_ins` has mismatched `run_id`",
|
164
175
|
)
|
165
176
|
|
166
177
|
# Store each TaskIns
|
@@ -199,7 +210,9 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
|
|
199
210
|
# Validate request
|
200
211
|
for task_res in task_res_list:
|
201
212
|
_raise_if(
|
202
|
-
request.run_id != task_res.run_id,
|
213
|
+
validation_error=request.run_id != task_res.run_id,
|
214
|
+
request_name="PullTaskRes",
|
215
|
+
detail="`task_res` has mismatched `run_id`",
|
203
216
|
)
|
204
217
|
|
205
218
|
# Delete the TaskIns/TaskRes pairs if TaskRes is found
|
@@ -344,6 +357,7 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
|
|
344
357
|
return GetRunStatusResponse(run_status_dict=run_status_dict)
|
345
358
|
|
346
359
|
|
347
|
-
def _raise_if(validation_error: bool, detail: str) -> None:
|
360
|
+
def _raise_if(validation_error: bool, request_name: str, detail: str) -> None:
|
361
|
+
"""Raise a `ValueError` with a detailed message if a validation error occurs."""
|
348
362
|
if validation_error:
|
349
|
-
raise ValueError(f"Malformed
|
363
|
+
raise ValueError(f"Malformed {request_name}: {detail}")
|
@@ -30,8 +30,12 @@ from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
30
30
|
DeleteNodeResponse,
|
31
31
|
PingRequest,
|
32
32
|
PingResponse,
|
33
|
+
PullMessagesRequest,
|
34
|
+
PullMessagesResponse,
|
33
35
|
PullTaskInsRequest,
|
34
36
|
PullTaskInsResponse,
|
37
|
+
PushMessagesRequest,
|
38
|
+
PushMessagesResponse,
|
35
39
|
PushTaskResRequest,
|
36
40
|
PushTaskResResponse,
|
37
41
|
)
|
@@ -95,6 +99,12 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
|
|
95
99
|
state=self.state_factory.state(),
|
96
100
|
)
|
97
101
|
|
102
|
+
def PullMessages(
|
103
|
+
self, request: PullMessagesRequest, context: grpc.ServicerContext
|
104
|
+
) -> PullMessagesResponse:
|
105
|
+
"""Pull Messages."""
|
106
|
+
return PullMessagesResponse()
|
107
|
+
|
98
108
|
def PushTaskRes(
|
99
109
|
self, request: PushTaskResRequest, context: grpc.ServicerContext
|
100
110
|
) -> PushTaskResResponse:
|
@@ -118,6 +128,12 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
|
|
118
128
|
|
119
129
|
return res
|
120
130
|
|
131
|
+
def PushMessages(
|
132
|
+
self, request: PushMessagesRequest, context: grpc.ServicerContext
|
133
|
+
) -> PushMessagesResponse:
|
134
|
+
"""Push Messages."""
|
135
|
+
return PushMessagesResponse()
|
136
|
+
|
121
137
|
def GetRun(
|
122
138
|
self, request: GetRunRequest, context: grpc.ServicerContext
|
123
139
|
) -> GetRunResponse:
|
@@ -223,5 +223,6 @@ class AuthenticateServerInterceptor(grpc.ServerInterceptor): # type: ignore
|
|
223
223
|
# No `node_id` exists for the provided `public_key`
|
224
224
|
# Handle `CreateNode` here instead of calling the default method handler
|
225
225
|
# Note: the innermost `CreateNode` method will never be called
|
226
|
-
node_id = state.create_node(request.ping_interval
|
226
|
+
node_id = state.create_node(request.ping_interval)
|
227
|
+
state.set_node_public_key(node_id, public_key_bytes)
|
227
228
|
return CreateNodeResponse(node=Node(node_id=node_id, anonymous=False))
|
@@ -62,6 +62,7 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
62
62
|
# Map node_id to (online_until, ping_interval)
|
63
63
|
self.node_ids: dict[int, tuple[float, float]] = {}
|
64
64
|
self.public_key_to_node_id: dict[bytes, int] = {}
|
65
|
+
self.node_id_to_public_key: dict[int, bytes] = {}
|
65
66
|
|
66
67
|
# Map run_id to RunRecord
|
67
68
|
self.run_ids: dict[int, RunRecord] = {}
|
@@ -306,9 +307,7 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
306
307
|
"""
|
307
308
|
return len(self.task_res_store)
|
308
309
|
|
309
|
-
def create_node(
|
310
|
-
self, ping_interval: float, public_key: Optional[bytes] = None
|
311
|
-
) -> int:
|
310
|
+
def create_node(self, ping_interval: float) -> int:
|
312
311
|
"""Create, store in the link state, and return `node_id`."""
|
313
312
|
# Sample a random int64 as node_id
|
314
313
|
node_id = generate_rand_int_from_bytes(NODE_ID_NUM_BYTES)
|
@@ -318,33 +317,18 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
318
317
|
log(ERROR, "Unexpected node registration failure.")
|
319
318
|
return 0
|
320
319
|
|
321
|
-
if public_key is not None:
|
322
|
-
if (
|
323
|
-
public_key in self.public_key_to_node_id
|
324
|
-
or node_id in self.public_key_to_node_id.values()
|
325
|
-
):
|
326
|
-
log(ERROR, "Unexpected node registration failure.")
|
327
|
-
return 0
|
328
|
-
|
329
|
-
self.public_key_to_node_id[public_key] = node_id
|
330
|
-
|
331
320
|
self.node_ids[node_id] = (time.time() + ping_interval, ping_interval)
|
332
321
|
return node_id
|
333
322
|
|
334
|
-
def delete_node(self, node_id: int
|
323
|
+
def delete_node(self, node_id: int) -> None:
|
335
324
|
"""Delete a node."""
|
336
325
|
with self.lock:
|
337
326
|
if node_id not in self.node_ids:
|
338
327
|
raise ValueError(f"Node {node_id} not found")
|
339
328
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
or node_id not in self.public_key_to_node_id.values()
|
344
|
-
):
|
345
|
-
raise ValueError("Public key or node_id not found")
|
346
|
-
|
347
|
-
del self.public_key_to_node_id[public_key]
|
329
|
+
# Remove node ID <> public key mappings
|
330
|
+
if pk := self.node_id_to_public_key.pop(node_id, None):
|
331
|
+
del self.public_key_to_node_id[pk]
|
348
332
|
|
349
333
|
del self.node_ids[node_id]
|
350
334
|
|
@@ -366,6 +350,26 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
366
350
|
if online_until > current_time
|
367
351
|
}
|
368
352
|
|
353
|
+
def set_node_public_key(self, node_id: int, public_key: bytes) -> None:
|
354
|
+
"""Set `public_key` for the specified `node_id`."""
|
355
|
+
with self.lock:
|
356
|
+
if node_id not in self.node_ids:
|
357
|
+
raise ValueError(f"Node {node_id} not found")
|
358
|
+
|
359
|
+
if public_key in self.public_key_to_node_id:
|
360
|
+
raise ValueError("Public key already in use")
|
361
|
+
|
362
|
+
self.public_key_to_node_id[public_key] = node_id
|
363
|
+
self.node_id_to_public_key[node_id] = public_key
|
364
|
+
|
365
|
+
def get_node_public_key(self, node_id: int) -> Optional[bytes]:
|
366
|
+
"""Get `public_key` for the specified `node_id`."""
|
367
|
+
with self.lock:
|
368
|
+
if node_id not in self.node_ids:
|
369
|
+
raise ValueError(f"Node {node_id} not found")
|
370
|
+
|
371
|
+
return self.node_id_to_public_key.get(node_id)
|
372
|
+
|
369
373
|
def get_node_id(self, node_public_key: bytes) -> Optional[int]:
|
370
374
|
"""Retrieve stored `node_id` filtered by `node_public_keys`."""
|
371
375
|
return self.public_key_to_node_id.get(node_public_key)
|
@@ -154,13 +154,11 @@ class LinkState(abc.ABC): # pylint: disable=R0904
|
|
154
154
|
"""Get all TaskIns IDs for the given run_id."""
|
155
155
|
|
156
156
|
@abc.abstractmethod
|
157
|
-
def create_node(
|
158
|
-
self, ping_interval: float, public_key: Optional[bytes] = None
|
159
|
-
) -> int:
|
157
|
+
def create_node(self, ping_interval: float) -> int:
|
160
158
|
"""Create, store in the link state, and return `node_id`."""
|
161
159
|
|
162
160
|
@abc.abstractmethod
|
163
|
-
def delete_node(self, node_id: int
|
161
|
+
def delete_node(self, node_id: int) -> None:
|
164
162
|
"""Remove `node_id` from the link state."""
|
165
163
|
|
166
164
|
@abc.abstractmethod
|
@@ -173,6 +171,14 @@ class LinkState(abc.ABC): # pylint: disable=R0904
|
|
173
171
|
an empty `Set` MUST be returned.
|
174
172
|
"""
|
175
173
|
|
174
|
+
@abc.abstractmethod
|
175
|
+
def set_node_public_key(self, node_id: int, public_key: bytes) -> None:
|
176
|
+
"""Set `public_key` for the specified `node_id`."""
|
177
|
+
|
178
|
+
@abc.abstractmethod
|
179
|
+
def get_node_public_key(self, node_id: int) -> Optional[bytes]:
|
180
|
+
"""Get `public_key` for the specified `node_id`."""
|
181
|
+
|
176
182
|
@abc.abstractmethod
|
177
183
|
def get_node_id(self, node_public_key: bytes) -> Optional[int]:
|
178
184
|
"""Retrieve stored `node_id` filtered by `node_public_keys`."""
|
@@ -72,14 +72,14 @@ CREATE TABLE IF NOT EXISTS node(
|
|
72
72
|
|
73
73
|
SQL_CREATE_TABLE_CREDENTIAL = """
|
74
74
|
CREATE TABLE IF NOT EXISTS credential(
|
75
|
-
private_key
|
76
|
-
public_key
|
75
|
+
private_key BLOB PRIMARY KEY,
|
76
|
+
public_key BLOB
|
77
77
|
);
|
78
78
|
"""
|
79
79
|
|
80
80
|
SQL_CREATE_TABLE_PUBLIC_KEY = """
|
81
81
|
CREATE TABLE IF NOT EXISTS public_key(
|
82
|
-
public_key
|
82
|
+
public_key BLOB PRIMARY KEY
|
83
83
|
);
|
84
84
|
"""
|
85
85
|
|
@@ -635,9 +635,7 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
635
635
|
|
636
636
|
return {UUID(row["task_id"]) for row in rows}
|
637
637
|
|
638
|
-
def create_node(
|
639
|
-
self, ping_interval: float, public_key: Optional[bytes] = None
|
640
|
-
) -> int:
|
638
|
+
def create_node(self, ping_interval: float) -> int:
|
641
639
|
"""Create, store in the link state, and return `node_id`."""
|
642
640
|
# Sample a random uint64 as node_id
|
643
641
|
uint64_node_id = generate_rand_int_from_bytes(NODE_ID_NUM_BYTES)
|
@@ -645,13 +643,6 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
645
643
|
# Convert the uint64 value to sint64 for SQLite
|
646
644
|
sint64_node_id = convert_uint64_to_sint64(uint64_node_id)
|
647
645
|
|
648
|
-
query = "SELECT node_id FROM node WHERE public_key = :public_key;"
|
649
|
-
row = self.query(query, {"public_key": public_key})
|
650
|
-
|
651
|
-
if len(row) > 0:
|
652
|
-
log(ERROR, "Unexpected node registration failure.")
|
653
|
-
return 0
|
654
|
-
|
655
646
|
query = (
|
656
647
|
"INSERT INTO node "
|
657
648
|
"(node_id, online_until, ping_interval, public_key) "
|
@@ -665,7 +656,7 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
665
656
|
sint64_node_id,
|
666
657
|
time.time() + ping_interval,
|
667
658
|
ping_interval,
|
668
|
-
|
659
|
+
b"", # Initialize with an empty public key
|
669
660
|
),
|
670
661
|
)
|
671
662
|
except sqlite3.IntegrityError:
|
@@ -675,7 +666,7 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
675
666
|
# Note: we need to return the uint64 value of the node_id
|
676
667
|
return uint64_node_id
|
677
668
|
|
678
|
-
def delete_node(self, node_id: int
|
669
|
+
def delete_node(self, node_id: int) -> None:
|
679
670
|
"""Delete a node."""
|
680
671
|
# Convert the uint64 value to sint64 for SQLite
|
681
672
|
sint64_node_id = convert_uint64_to_sint64(node_id)
|
@@ -683,10 +674,6 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
683
674
|
query = "DELETE FROM node WHERE node_id = ?"
|
684
675
|
params = (sint64_node_id,)
|
685
676
|
|
686
|
-
if public_key is not None:
|
687
|
-
query += " AND public_key = ?"
|
688
|
-
params += (public_key,) # type: ignore
|
689
|
-
|
690
677
|
if self.conn is None:
|
691
678
|
raise AttributeError("LinkState is not initialized.")
|
692
679
|
|
@@ -694,7 +681,7 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
694
681
|
with self.conn:
|
695
682
|
rows = self.conn.execute(query, params)
|
696
683
|
if rows.rowcount < 1:
|
697
|
-
raise ValueError("
|
684
|
+
raise ValueError(f"Node {node_id} not found")
|
698
685
|
except KeyError as exc:
|
699
686
|
log(ERROR, {"query": query, "data": params, "exception": exc})
|
700
687
|
|
@@ -722,6 +709,41 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
722
709
|
result: set[int] = {convert_sint64_to_uint64(row["node_id"]) for row in rows}
|
723
710
|
return result
|
724
711
|
|
712
|
+
def set_node_public_key(self, node_id: int, public_key: bytes) -> None:
|
713
|
+
"""Set `public_key` for the specified `node_id`."""
|
714
|
+
# Convert the uint64 value to sint64 for SQLite
|
715
|
+
sint64_node_id = convert_uint64_to_sint64(node_id)
|
716
|
+
|
717
|
+
# Check if the node exists in the `node` table
|
718
|
+
query = "SELECT 1 FROM node WHERE node_id = ?"
|
719
|
+
if not self.query(query, (sint64_node_id,)):
|
720
|
+
raise ValueError(f"Node {node_id} not found")
|
721
|
+
|
722
|
+
# Check if the public key is already in use in the `node` table
|
723
|
+
query = "SELECT 1 FROM node WHERE public_key = ?"
|
724
|
+
if self.query(query, (public_key,)):
|
725
|
+
raise ValueError("Public key already in use")
|
726
|
+
|
727
|
+
# Update the `node` table to set the public key for the given node ID
|
728
|
+
query = "UPDATE node SET public_key = ? WHERE node_id = ?"
|
729
|
+
self.query(query, (public_key, sint64_node_id))
|
730
|
+
|
731
|
+
def get_node_public_key(self, node_id: int) -> Optional[bytes]:
|
732
|
+
"""Get `public_key` for the specified `node_id`."""
|
733
|
+
# Convert the uint64 value to sint64 for SQLite
|
734
|
+
sint64_node_id = convert_uint64_to_sint64(node_id)
|
735
|
+
|
736
|
+
# Query the public key for the given node_id
|
737
|
+
query = "SELECT public_key FROM node WHERE node_id = ?"
|
738
|
+
rows = self.query(query, (sint64_node_id,))
|
739
|
+
|
740
|
+
# If no result is found, return None
|
741
|
+
if not rows:
|
742
|
+
raise ValueError(f"Node {node_id} not found")
|
743
|
+
|
744
|
+
# Return the public key if it is not empty, otherwise return None
|
745
|
+
return rows[0]["public_key"] or None
|
746
|
+
|
725
747
|
def get_node_id(self, node_public_key: bytes) -> Optional[int]:
|
726
748
|
"""Retrieve stored `node_id` filtered by `node_public_keys`."""
|
727
749
|
query = "SELECT node_id FROM node WHERE public_key = :public_key;"
|
{flwr_nightly-1.15.0.dev20250108.dist-info → flwr_nightly-1.15.0.dev20250109.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: flwr-nightly
|
3
|
-
Version: 1.15.0.
|
3
|
+
Version: 1.15.0.dev20250109
|
4
4
|
Summary: Flower: A Friendly Federated AI Framework
|
5
5
|
Home-page: https://flower.ai
|
6
6
|
License: Apache-2.0
|
@@ -88,7 +88,7 @@ design of Flower is based on a few guiding principles:
|
|
88
88
|
|
89
89
|
- **Framework-agnostic**: Different machine learning frameworks have different
|
90
90
|
strengths. Flower can be used with any machine learning framework, for
|
91
|
-
example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [MONAI](https://docs.monai.io/en/latest/index.html), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
|
91
|
+
example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [MONAI](https://docs.monai.io/en/latest/index.html), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [LeRobot](https://github.com/huggingface/lerobot) for federated robots, [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
|
92
92
|
for users who enjoy computing gradients by hand.
|
93
93
|
|
94
94
|
- **Understandable**: Flower is written with maintainability in mind. The
|
{flwr_nightly-1.15.0.dev20250108.dist-info → flwr_nightly-1.15.0.dev20250109.dist-info}/RECORD
RENAMED
@@ -82,9 +82,9 @@ flwr/client/grpc_adapter_client/connection.py,sha256=nV-hPd5q5Eblg6PgUrGGYj74mbE
|
|
82
82
|
flwr/client/grpc_client/__init__.py,sha256=LsnbqXiJhgQcB0XzAlUQgPx011Uf7Y7yabIC1HxivJ8,735
|
83
83
|
flwr/client/grpc_client/connection.py,sha256=gMwB87mlmRBbvPOvUA1m3C-Ci6bjMEmTRI4bJpgbyic,9416
|
84
84
|
flwr/client/grpc_rere_client/__init__.py,sha256=MK-oSoV3kwUEQnIwl0GN4OpiHR7eLOrMA8ikunET130,752
|
85
|
-
flwr/client/grpc_rere_client/client_interceptor.py,sha256=
|
85
|
+
flwr/client/grpc_rere_client/client_interceptor.py,sha256=9BEZNOHxNJFxIuXc9KzBF0ZkXECtOm7RgnZ9yHVUxCQ,5554
|
86
86
|
flwr/client/grpc_rere_client/connection.py,sha256=NqKSoYIJblB4lElZ7EKIgDjLb6KYEcI-7CBrTbyiKfg,11475
|
87
|
-
flwr/client/grpc_rere_client/grpc_adapter.py,sha256=
|
87
|
+
flwr/client/grpc_rere_client/grpc_adapter.py,sha256=VrSqHosRcWv8xDLKEabuzyHpVnRhjAEJf_MUFQxhDh8,6155
|
88
88
|
flwr/client/heartbeat.py,sha256=cx37mJBH8LyoIN4Lks85wtqT1mnU5GulQnr4pGCvAq0,2404
|
89
89
|
flwr/client/message_handler/__init__.py,sha256=QxxQuBNpFPTHx3KiUNvQSlqMKlEnbRR1kFfc1KVje08,719
|
90
90
|
flwr/client/message_handler/message_handler.py,sha256=s7FEfYJp5QB259Pj1L94_9AC24Kh5JyKC2U-E6eNkkY,6492
|
@@ -165,10 +165,10 @@ flwr/proto/fab_pb2.py,sha256=-gfW_ePYHx1vDGHfimwn91qEhmmY_gslaOHwqqZnVdU,1627
|
|
165
165
|
flwr/proto/fab_pb2.pyi,sha256=AMXpiDK0fo3nZWjxsC2E4otSaVjyQbU7iiWKrsSZavs,2395
|
166
166
|
flwr/proto/fab_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
167
167
|
flwr/proto/fab_pb2_grpc.pyi,sha256=ff2TSiLVnG6IVQcTGzb2DIH3XRSoAvAo_RMcvbMFyc0,76
|
168
|
-
flwr/proto/fleet_pb2.py,sha256=
|
169
|
-
flwr/proto/fleet_pb2.pyi,sha256=
|
170
|
-
flwr/proto/fleet_pb2_grpc.py,sha256=
|
171
|
-
flwr/proto/fleet_pb2_grpc.pyi,sha256=
|
168
|
+
flwr/proto/fleet_pb2.py,sha256=Uu_oFKPBTzkROKWQmFN59jFucGagtvMjHqkgz6PhlLM,6583
|
169
|
+
flwr/proto/fleet_pb2.pyi,sha256=XT8Y79QB9ZWljt30hGmytkxJbu6H_D7ltkYopJQFM4o,12004
|
170
|
+
flwr/proto/fleet_pb2_grpc.py,sha256=J1rR8nr3_LFzaBfocZdgFj8xIXUaJDOMCN-G2-Rs-hU,15510
|
171
|
+
flwr/proto/fleet_pb2_grpc.pyi,sha256=BsqtyvC2GSqB40efort63LG2wRIKTp4eI8aOr9rbU1Y,3928
|
172
172
|
flwr/proto/grpcadapter_pb2.py,sha256=bb8mW09XzNCpMdr1KuYQkefPFWR8lc8y1uL6Uk0TtsM,1843
|
173
173
|
flwr/proto/grpcadapter_pb2.pyi,sha256=AR77gDsF6f8zqSIQp3877DUd7S8lP95lFak5Ir_WPkw,1716
|
174
174
|
flwr/proto/grpcadapter_pb2_grpc.py,sha256=rRNuNES5nBugUZWfeA8oAy8dMHgzqU_PF1srTseo3b8,2634
|
@@ -259,7 +259,7 @@ flwr/server/strategy/strategy.py,sha256=cXapkD5uDrt5C-RbmWDn9FLoap3Q41i7GKvbmfbC
|
|
259
259
|
flwr/server/superlink/__init__.py,sha256=8tHYCfodUlRD8PCP9fHgvu8cz5N31A2QoRVL0jDJ15E,707
|
260
260
|
flwr/server/superlink/driver/__init__.py,sha256=5soEK5QSvxNjmJQ-CGTWROc4alSAeU0e9Ad9RDhsd3E,717
|
261
261
|
flwr/server/superlink/driver/serverappio_grpc.py,sha256=62371xIRzp3k-eQTaSpb9c4TiSfueSuI7Iw5X3IafOY,2186
|
262
|
-
flwr/server/superlink/driver/serverappio_servicer.py,sha256=
|
262
|
+
flwr/server/superlink/driver/serverappio_servicer.py,sha256=4QEwqm_pew1iVbtEZuOWLhfgbbw4LIUwFjOuGBlPJZY,12747
|
263
263
|
flwr/server/superlink/ffs/__init__.py,sha256=FAY-zShcfPmOxosok2QyT6hTNMNctG8cH9s_nIl8jkI,840
|
264
264
|
flwr/server/superlink/ffs/disk_ffs.py,sha256=n_Ah0sQwXGVQ9wj5965nLjdkQQbpoHCljjXKFnwftsU,3297
|
265
265
|
flwr/server/superlink/ffs/ffs.py,sha256=qLI1UfosJugu2BKOJWqHIhafTm-YiuKqGf3OGWPH0NM,2395
|
@@ -273,8 +273,8 @@ flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py,sha256=JkAH_nIZaqe_9kntrg26
|
|
273
273
|
flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py,sha256=h3EhqgelegVC4EjOXH5birmAnMoCBJcP7jpHYCnHZPk,4887
|
274
274
|
flwr/server/superlink/fleet/grpc_bidi/grpc_server.py,sha256=X4I2rd1ZC9fqjOg9uwdTydLxJ3JiWthkIAqb3wEv17g,12454
|
275
275
|
flwr/server/superlink/fleet/grpc_rere/__init__.py,sha256=j2hyC342am-_Hgp1g80Y3fGDzfTI6n8QOOn2PyWf4eg,758
|
276
|
-
flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=
|
277
|
-
flwr/server/superlink/fleet/grpc_rere/server_interceptor.py,sha256=
|
276
|
+
flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=PyZP78gHU_RIRVSlPjyAvKG6UOLSilopkT6zoC_6ASc,5881
|
277
|
+
flwr/server/superlink/fleet/grpc_rere/server_interceptor.py,sha256=SKa1wfBNxJL6vGBUbbTgUylY3ZHJMyBSZRC1J6PBvyY,8342
|
278
278
|
flwr/server/superlink/fleet/message_handler/__init__.py,sha256=h8oLD7uo5lKICPy0rRdKRjTYe62u8PKkT_fA4xF5JPA,731
|
279
279
|
flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=hzL8t6uUqO1lu5UHLF_NerdJuce4S5cK9fIWkKDzJfA,5298
|
280
280
|
flwr/server/superlink/fleet/rest_rere/__init__.py,sha256=5jbYbAn75sGv-gBwOPDySE0kz96F6dTYLeMrGqNi4lM,735
|
@@ -285,10 +285,10 @@ flwr/server/superlink/fleet/vce/backend/backend.py,sha256=LBAQxnbfPAphVOVIvYMj0Q
|
|
285
285
|
flwr/server/superlink/fleet/vce/backend/raybackend.py,sha256=jsUkFEVQTnrucK1jNQ_cUM8YwL7W4MQNA1GAf8ibRdg,7156
|
286
286
|
flwr/server/superlink/fleet/vce/vce_api.py,sha256=WTnUILr1OHS8LfjXQUA3FyWJYdJgdqpFAybyJUD-1Xo,13025
|
287
287
|
flwr/server/superlink/linkstate/__init__.py,sha256=v-2JyJlCB3qyhMNwMjmcNVOq4rkooqFU0LHH8Zo1jls,1064
|
288
|
-
flwr/server/superlink/linkstate/in_memory_linkstate.py,sha256=
|
289
|
-
flwr/server/superlink/linkstate/linkstate.py,sha256=
|
288
|
+
flwr/server/superlink/linkstate/in_memory_linkstate.py,sha256=yYLIzFurLTw5L5KscLYF6VBEBo1i-GFuSjBW2ij-7V0,22230
|
289
|
+
flwr/server/superlink/linkstate/linkstate.py,sha256=NAdArILJ58TUif-K-LzUVfgqcMdqb0719GYAV3gu0n4,13342
|
290
290
|
flwr/server/superlink/linkstate/linkstate_factory.py,sha256=ISSMjDlwuN7swxjOeYlTNpI_kuZ8PGkMcJnf1dbhUSE,2069
|
291
|
-
flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=
|
291
|
+
flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=lLvVAscwVioqzj4uj0WfDUyoq-L7Nr-kMKCdaGPI0Z8,44050
|
292
292
|
flwr/server/superlink/linkstate/utils.py,sha256=d5uqqIOCKfd54X8CFNfUr3AWqPLpgmzsC_RagRwFugM,13321
|
293
293
|
flwr/server/superlink/simulation/__init__.py,sha256=mg-oapC9dkzEfjXPQFior5lpWj4g9kwbLovptyYM_g0,718
|
294
294
|
flwr/server/superlink/simulation/simulationio_grpc.py,sha256=5wflYW_TS0mjmPG6OYuHMJwXD2_cYmUNhFkdOU0jMWQ,2237
|
@@ -321,8 +321,8 @@ flwr/superexec/exec_servicer.py,sha256=X10ILT-AoGMrB3IgI2mBe9i-QcIVUAl9bucuqVOPY
|
|
321
321
|
flwr/superexec/exec_user_auth_interceptor.py,sha256=K06OU-l4LnYhTDg071hGJuOaQWEJbZsYi5qxUmmtiG0,3704
|
322
322
|
flwr/superexec/executor.py,sha256=_B55WW2TD1fBINpabSSDRenVHXYmvlfhv-k8hJKU4lQ,3115
|
323
323
|
flwr/superexec/simulation.py,sha256=WQDon15oqpMopAZnwRZoTICYCfHqtkvFSqiTQ2hLD_g,4088
|
324
|
-
flwr_nightly-1.15.0.
|
325
|
-
flwr_nightly-1.15.0.
|
326
|
-
flwr_nightly-1.15.0.
|
327
|
-
flwr_nightly-1.15.0.
|
328
|
-
flwr_nightly-1.15.0.
|
324
|
+
flwr_nightly-1.15.0.dev20250109.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
325
|
+
flwr_nightly-1.15.0.dev20250109.dist-info/METADATA,sha256=bx7_AOmer-gS3TN_YLCG0WVJFPIXNgyGE6ovkxjiGDg,15882
|
326
|
+
flwr_nightly-1.15.0.dev20250109.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
327
|
+
flwr_nightly-1.15.0.dev20250109.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
|
328
|
+
flwr_nightly-1.15.0.dev20250109.dist-info/RECORD,,
|
{flwr_nightly-1.15.0.dev20250108.dist-info → flwr_nightly-1.15.0.dev20250109.dist-info}/LICENSE
RENAMED
File without changes
|
{flwr_nightly-1.15.0.dev20250108.dist-info → flwr_nightly-1.15.0.dev20250109.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|