flwr-nightly 1.15.0.dev20250108__py3-none-any.whl → 1.15.0.dev20250110__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/app.py CHANGED
@@ -15,13 +15,14 @@
15
15
  """Flower client app."""
16
16
 
17
17
 
18
+ import multiprocessing
18
19
  import signal
19
- import subprocess
20
20
  import sys
21
21
  import time
22
22
  from contextlib import AbstractContextManager
23
23
  from dataclasses import dataclass
24
24
  from logging import ERROR, INFO, WARN
25
+ from os import urandom
25
26
  from pathlib import Path
26
27
  from typing import Callable, Optional, Union, cast
27
28
 
@@ -33,6 +34,7 @@ from flwr.cli.config_utils import get_fab_metadata
33
34
  from flwr.cli.install import install_from_fab
34
35
  from flwr.client.client import Client
35
36
  from flwr.client.client_app import ClientApp, LoadClientAppError
37
+ from flwr.client.clientapp.app import flwr_clientapp
36
38
  from flwr.client.nodestate.nodestate_factory import NodeStateFactory
37
39
  from flwr.client.typing import ClientFnExt
38
40
  from flwr.common import GRPC_MAX_MESSAGE_LENGTH, Context, EventType, Message, event
@@ -53,13 +55,12 @@ from flwr.common.constant import (
53
55
  TRANSPORT_TYPES,
54
56
  ErrorCode,
55
57
  )
58
+ from flwr.common.grpc import generic_create_grpc_server
56
59
  from flwr.common.logger import log, warn_deprecated_feature
57
60
  from flwr.common.message import Error
58
61
  from flwr.common.retry_invoker import RetryInvoker, RetryState, exponential
59
62
  from flwr.common.typing import Fab, Run, RunNotRunningException, UserConfig
60
63
  from flwr.proto.clientappio_pb2_grpc import add_ClientAppIoServicer_to_server
61
- from flwr.server.superlink.fleet.grpc_bidi.grpc_server import generic_create_grpc_server
62
- from flwr.server.superlink.linkstate.utils import generate_rand_int_from_bytes
63
64
 
64
65
  from .clientapp.clientappio_servicer import ClientAppInputs, ClientAppIoServicer
65
66
  from .grpc_adapter_client.connection import grpc_adapter
@@ -391,6 +392,7 @@ def start_client_internal(
391
392
  run_info_store: Optional[DeprecatedRunInfoStore] = None
392
393
  state_factory = NodeStateFactory()
393
394
  state = state_factory.state()
395
+ mp_spawn_context = multiprocessing.get_context("spawn")
394
396
 
395
397
  runs: dict[int, Run] = {}
396
398
 
@@ -513,7 +515,7 @@ def start_client_internal(
513
515
  # Docker container.
514
516
 
515
517
  # Generate SuperNode token
516
- token: int = generate_rand_int_from_bytes(RUN_ID_NUM_BYTES)
518
+ token = int.from_bytes(urandom(RUN_ID_NUM_BYTES), "little")
517
519
 
518
520
  # Mode 1: SuperNode starts ClientApp as subprocess
519
521
  start_subprocess = isolation == ISOLATION_MODE_SUBPROCESS
@@ -549,12 +551,13 @@ def start_client_internal(
549
551
  ]
550
552
  command.append("--insecure")
551
553
 
552
- subprocess.run(
553
- command,
554
- stdout=None,
555
- stderr=None,
556
- check=True,
554
+ proc = mp_spawn_context.Process(
555
+ target=_run_flwr_clientapp,
556
+ args=(command,),
557
+ daemon=True,
557
558
  )
559
+ proc.start()
560
+ proc.join()
558
561
  else:
559
562
  # Wait for output to become available
560
563
  while not clientappio_servicer.has_outputs():
@@ -826,6 +829,11 @@ class _AppStateTracker:
826
829
  signal.signal(signal.SIGTERM, signal_handler)
827
830
 
828
831
 
832
+ def _run_flwr_clientapp(args: list[str]) -> None:
833
+ sys.argv = args
834
+ flwr_clientapp()
835
+
836
+
829
837
  def run_clientappio_api_grpc(
830
838
  address: str,
831
839
  certificates: Optional[tuple[bytes, bytes, bytes]],
@@ -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/common/grpc.py CHANGED
@@ -15,16 +15,26 @@
15
15
  """Utility functions for gRPC."""
16
16
 
17
17
 
18
+ import concurrent.futures
19
+ import sys
18
20
  from collections.abc import Sequence
19
- from logging import DEBUG
20
- from typing import Optional
21
+ from logging import DEBUG, ERROR
22
+ from typing import Any, Callable, Optional
21
23
 
22
24
  import grpc
23
25
 
24
- from flwr.common.logger import log
26
+ from .address import is_port_in_use
27
+ from .logger import log
25
28
 
26
29
  GRPC_MAX_MESSAGE_LENGTH: int = 536_870_912 # == 512 * 1024 * 1024
27
30
 
31
+ INVALID_CERTIFICATES_ERR_MSG = """
32
+ When setting any of root_certificate, certificate, or private_key,
33
+ all of them need to be set.
34
+ """
35
+
36
+ AddServicerToServerFn = Callable[..., Any]
37
+
28
38
 
29
39
  def create_channel(
30
40
  server_address: str,
@@ -66,3 +76,144 @@ def create_channel(
66
76
  channel = grpc.intercept_channel(channel, interceptors)
67
77
 
68
78
  return channel
79
+
80
+
81
+ def valid_certificates(certificates: tuple[bytes, bytes, bytes]) -> bool:
82
+ """Validate certificates tuple."""
83
+ is_valid = (
84
+ all(isinstance(certificate, bytes) for certificate in certificates)
85
+ and len(certificates) == 3
86
+ )
87
+
88
+ if not is_valid:
89
+ log(ERROR, INVALID_CERTIFICATES_ERR_MSG)
90
+
91
+ return is_valid
92
+
93
+
94
+ def generic_create_grpc_server( # pylint: disable=too-many-arguments,R0917
95
+ servicer_and_add_fn: tuple[Any, AddServicerToServerFn],
96
+ server_address: str,
97
+ max_concurrent_workers: int = 1000,
98
+ max_message_length: int = GRPC_MAX_MESSAGE_LENGTH,
99
+ keepalive_time_ms: int = 210000,
100
+ certificates: Optional[tuple[bytes, bytes, bytes]] = None,
101
+ interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None,
102
+ ) -> grpc.Server:
103
+ """Create a gRPC server with a single servicer.
104
+
105
+ Parameters
106
+ ----------
107
+ servicer_and_add_fn : tuple
108
+ A tuple holding a servicer implementation and a matching
109
+ add_Servicer_to_server function.
110
+ server_address : str
111
+ Server address in the form of HOST:PORT e.g. "[::]:8080"
112
+ max_concurrent_workers : int
113
+ Maximum number of clients the server can process before returning
114
+ RESOURCE_EXHAUSTED status (default: 1000)
115
+ max_message_length : int
116
+ Maximum message length that the server can send or receive.
117
+ Int valued in bytes. -1 means unlimited. (default: GRPC_MAX_MESSAGE_LENGTH)
118
+ keepalive_time_ms : int
119
+ Flower uses a default gRPC keepalive time of 210000ms (3 minutes 30 seconds)
120
+ because some cloud providers (for example, Azure) agressively clean up idle
121
+ TCP connections by terminating them after some time (4 minutes in the case
122
+ of Azure). Flower does not use application-level keepalive signals and relies
123
+ on the assumption that the transport layer will fail in cases where the
124
+ connection is no longer active. `keepalive_time_ms` can be used to customize
125
+ the keepalive interval for specific environments. The default Flower gRPC
126
+ keepalive of 210000 ms (3 minutes 30 seconds) ensures that Flower can keep
127
+ the long running streaming connection alive in most environments. The actual
128
+ gRPC default of this setting is 7200000 (2 hours), which results in dropped
129
+ connections in some cloud environments.
130
+
131
+ These settings are related to the issue described here:
132
+ - https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md
133
+ - https://github.com/grpc/grpc/blob/master/doc/keepalive.md
134
+ - https://grpc.io/docs/guides/performance/
135
+
136
+ Mobile Flower clients may choose to increase this value if their server
137
+ environment allows long-running idle TCP connections.
138
+ (default: 210000)
139
+ certificates : Tuple[bytes, bytes, bytes] (default: None)
140
+ Tuple containing root certificate, server certificate, and private key to
141
+ start a secure SSL-enabled server. The tuple is expected to have three bytes
142
+ elements in the following order:
143
+
144
+ * CA certificate.
145
+ * server certificate.
146
+ * server private key.
147
+ interceptors : Optional[Sequence[grpc.ServerInterceptor]] (default: None)
148
+ A list of gRPC interceptors.
149
+
150
+ Returns
151
+ -------
152
+ server : grpc.Server
153
+ A non-running instance of a gRPC server.
154
+ """
155
+ # Check if port is in use
156
+ if is_port_in_use(server_address):
157
+ sys.exit(f"Port in server address {server_address} is already in use.")
158
+
159
+ # Deconstruct tuple into servicer and function
160
+ servicer, add_servicer_to_server_fn = servicer_and_add_fn
161
+
162
+ # Possible options:
163
+ # https://github.com/grpc/grpc/blob/v1.43.x/include/grpc/impl/codegen/grpc_types.h
164
+ options = [
165
+ # Maximum number of concurrent incoming streams to allow on a http2
166
+ # connection. Int valued.
167
+ ("grpc.max_concurrent_streams", max(100, max_concurrent_workers)),
168
+ # Maximum message length that the channel can send.
169
+ # Int valued, bytes. -1 means unlimited.
170
+ ("grpc.max_send_message_length", max_message_length),
171
+ # Maximum message length that the channel can receive.
172
+ # Int valued, bytes. -1 means unlimited.
173
+ ("grpc.max_receive_message_length", max_message_length),
174
+ # The gRPC default for this setting is 7200000 (2 hours). Flower uses a
175
+ # customized default of 210000 (3 minutes and 30 seconds) to improve
176
+ # compatibility with popular cloud providers. Mobile Flower clients may
177
+ # choose to increase this value if their server environment allows
178
+ # long-running idle TCP connections.
179
+ ("grpc.keepalive_time_ms", keepalive_time_ms),
180
+ # Setting this to zero will allow sending unlimited keepalive pings in between
181
+ # sending actual data frames.
182
+ ("grpc.http2.max_pings_without_data", 0),
183
+ # Is it permissible to send keepalive pings from the client without
184
+ # any outstanding streams. More explanation here:
185
+ # https://github.com/adap/flower/pull/2197
186
+ ("grpc.keepalive_permit_without_calls", 0),
187
+ ]
188
+
189
+ server = grpc.server(
190
+ concurrent.futures.ThreadPoolExecutor(max_workers=max_concurrent_workers),
191
+ # Set the maximum number of concurrent RPCs this server will service before
192
+ # returning RESOURCE_EXHAUSTED status, or None to indicate no limit.
193
+ maximum_concurrent_rpcs=max_concurrent_workers,
194
+ options=options,
195
+ interceptors=interceptors,
196
+ )
197
+ add_servicer_to_server_fn(servicer, server)
198
+
199
+ if certificates is not None:
200
+ if not valid_certificates(certificates):
201
+ sys.exit(1)
202
+
203
+ root_certificate_b, certificate_b, private_key_b = certificates
204
+
205
+ server_credentials = grpc.ssl_server_credentials(
206
+ ((private_key_b, certificate_b),),
207
+ root_certificates=root_certificate_b,
208
+ # A boolean indicating whether or not to require clients to be
209
+ # authenticated. May only be True if root_certificates is not None.
210
+ # We are explicitly setting the current gRPC default to document
211
+ # the option. For further reference see:
212
+ # https://grpc.github.io/grpc/python/grpc.html#create-server-credentials
213
+ require_client_auth=False,
214
+ )
215
+ server.add_secure_port(server_address, server_credentials)
216
+ else:
217
+ server.add_insecure_port(server_address)
218
+
219
+ return server
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\x8c\x04\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\x12P\n\x0bPushTaskRes\x12\x1e.flwr.proto.PushTaskResRequest\x1a\x1f.flwr.proto.PushTaskResResponse\"\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
+ 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['_CREATENODEREQUEST']._serialized_start=128
31
- _globals['_CREATENODEREQUEST']._serialized_end=170
32
- _globals['_CREATENODERESPONSE']._serialized_start=172
33
- _globals['_CREATENODERESPONSE']._serialized_end=224
34
- _globals['_DELETENODEREQUEST']._serialized_start=226
35
- _globals['_DELETENODEREQUEST']._serialized_end=277
36
- _globals['_DELETENODERESPONSE']._serialized_start=279
37
- _globals['_DELETENODERESPONSE']._serialized_end=299
38
- _globals['_PINGREQUEST']._serialized_start=301
39
- _globals['_PINGREQUEST']._serialized_end=369
40
- _globals['_PINGRESPONSE']._serialized_start=371
41
- _globals['_PINGRESPONSE']._serialized_end=402
42
- _globals['_PULLTASKINSREQUEST']._serialized_start=404
43
- _globals['_PULLTASKINSREQUEST']._serialized_end=474
44
- _globals['_PULLTASKINSRESPONSE']._serialized_start=476
45
- _globals['_PULLTASKINSRESPONSE']._serialized_end=583
46
- _globals['_PUSHTASKRESREQUEST']._serialized_start=585
47
- _globals['_PUSHTASKRESREQUEST']._serialized_end=681
48
- _globals['_PUSHTASKRESRESPONSE']._serialized_start=684
49
- _globals['_PUSHTASKRESRESPONSE']._serialized_end=858
50
- _globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._serialized_start=812
51
- _globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._serialized_end=858
52
- _globals['_RECONNECT']._serialized_start=860
53
- _globals['_RECONNECT']._serialized_end=890
54
- _globals['_FLEET']._serialized_start=893
55
- _globals['_FLEET']._serialized_end=1417
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
@@ -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,