flwr 1.18.0__py3-none-any.whl → 1.20.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.
- flwr/app/__init__.py +15 -0
- flwr/app/error.py +68 -0
- flwr/app/metadata.py +223 -0
- flwr/cli/build.py +94 -59
- flwr/cli/log.py +3 -3
- flwr/cli/login/login.py +3 -7
- flwr/cli/ls.py +15 -36
- flwr/cli/new/new.py +12 -4
- flwr/cli/new/templates/app/README.flowertune.md.tpl +2 -0
- flwr/cli/new/templates/app/README.md.tpl +5 -0
- flwr/cli/new/templates/app/code/client.baseline.py.tpl +1 -1
- flwr/cli/new/templates/app/code/model.baseline.py.tpl +1 -1
- flwr/cli/new/templates/app/code/server.baseline.py.tpl +2 -3
- flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +25 -17
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +13 -1
- flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +21 -2
- flwr/cli/new/templates/app/pyproject.jax.toml.tpl +18 -1
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +19 -2
- flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +18 -1
- flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +20 -3
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +18 -1
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +18 -1
- flwr/cli/run/run.py +48 -49
- flwr/cli/stop.py +2 -2
- flwr/cli/utils.py +38 -5
- flwr/client/__init__.py +2 -2
- flwr/client/client_app.py +1 -1
- flwr/client/clientapp/__init__.py +0 -7
- flwr/client/grpc_adapter_client/connection.py +15 -8
- flwr/client/grpc_rere_client/connection.py +142 -97
- flwr/client/grpc_rere_client/grpc_adapter.py +34 -6
- flwr/client/message_handler/message_handler.py +1 -1
- flwr/client/mod/comms_mods.py +36 -17
- flwr/client/rest_client/connection.py +176 -103
- flwr/clientapp/__init__.py +15 -0
- flwr/common/__init__.py +2 -2
- flwr/common/auth_plugin/__init__.py +2 -0
- flwr/common/auth_plugin/auth_plugin.py +29 -3
- flwr/common/constant.py +39 -8
- flwr/common/event_log_plugin/event_log_plugin.py +3 -3
- flwr/common/exit/exit_code.py +16 -1
- flwr/common/exit_handlers.py +30 -0
- flwr/common/grpc.py +12 -1
- flwr/common/heartbeat.py +165 -0
- flwr/common/inflatable.py +290 -0
- flwr/common/inflatable_protobuf_utils.py +141 -0
- flwr/common/inflatable_utils.py +508 -0
- flwr/common/message.py +110 -242
- flwr/common/record/__init__.py +2 -1
- flwr/common/record/array.py +402 -0
- flwr/common/record/arraychunk.py +59 -0
- flwr/common/record/arrayrecord.py +103 -225
- flwr/common/record/configrecord.py +59 -4
- flwr/common/record/conversion_utils.py +1 -1
- flwr/common/record/metricrecord.py +55 -4
- flwr/common/record/recorddict.py +69 -1
- flwr/common/recorddict_compat.py +2 -2
- flwr/common/retry_invoker.py +5 -1
- flwr/common/serde.py +59 -211
- flwr/common/serde_utils.py +175 -0
- flwr/common/typing.py +5 -3
- flwr/compat/__init__.py +15 -0
- flwr/compat/client/__init__.py +15 -0
- flwr/{client → compat/client}/app.py +28 -185
- flwr/compat/common/__init__.py +15 -0
- flwr/compat/server/__init__.py +15 -0
- flwr/compat/server/app.py +174 -0
- flwr/compat/simulation/__init__.py +15 -0
- flwr/proto/appio_pb2.py +43 -0
- flwr/proto/appio_pb2.pyi +151 -0
- flwr/proto/appio_pb2_grpc.py +4 -0
- flwr/proto/appio_pb2_grpc.pyi +4 -0
- flwr/proto/clientappio_pb2.py +12 -19
- flwr/proto/clientappio_pb2.pyi +23 -101
- flwr/proto/clientappio_pb2_grpc.py +269 -28
- flwr/proto/clientappio_pb2_grpc.pyi +114 -20
- flwr/proto/fleet_pb2.py +24 -27
- flwr/proto/fleet_pb2.pyi +19 -35
- flwr/proto/fleet_pb2_grpc.py +117 -13
- flwr/proto/fleet_pb2_grpc.pyi +47 -6
- flwr/proto/heartbeat_pb2.py +33 -0
- flwr/proto/heartbeat_pb2.pyi +66 -0
- flwr/proto/heartbeat_pb2_grpc.py +4 -0
- flwr/proto/heartbeat_pb2_grpc.pyi +4 -0
- flwr/proto/message_pb2.py +28 -11
- flwr/proto/message_pb2.pyi +125 -0
- flwr/proto/recorddict_pb2.py +16 -28
- flwr/proto/recorddict_pb2.pyi +46 -64
- flwr/proto/run_pb2.py +24 -32
- flwr/proto/run_pb2.pyi +4 -52
- flwr/proto/serverappio_pb2.py +9 -23
- flwr/proto/serverappio_pb2.pyi +0 -110
- flwr/proto/serverappio_pb2_grpc.py +177 -72
- flwr/proto/serverappio_pb2_grpc.pyi +75 -33
- flwr/proto/simulationio_pb2.py +12 -11
- flwr/proto/simulationio_pb2_grpc.py +35 -0
- flwr/proto/simulationio_pb2_grpc.pyi +14 -0
- flwr/server/__init__.py +1 -1
- flwr/server/app.py +69 -187
- flwr/server/compat/app_utils.py +50 -28
- flwr/server/fleet_event_log_interceptor.py +6 -2
- flwr/server/grid/grpc_grid.py +148 -41
- flwr/server/grid/inmemory_grid.py +5 -4
- flwr/server/serverapp/app.py +45 -17
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +21 -3
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +102 -8
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +2 -5
- flwr/server/superlink/fleet/message_handler/message_handler.py +130 -19
- flwr/server/superlink/fleet/rest_rere/rest_api.py +73 -13
- flwr/server/superlink/fleet/vce/vce_api.py +6 -3
- flwr/server/superlink/linkstate/in_memory_linkstate.py +138 -43
- flwr/server/superlink/linkstate/linkstate.py +53 -20
- flwr/server/superlink/linkstate/sqlite_linkstate.py +149 -55
- flwr/server/superlink/linkstate/utils.py +33 -29
- flwr/server/superlink/serverappio/serverappio_grpc.py +4 -1
- flwr/server/superlink/serverappio/serverappio_servicer.py +230 -84
- flwr/server/superlink/simulation/simulationio_grpc.py +1 -1
- flwr/server/superlink/simulation/simulationio_servicer.py +26 -2
- flwr/server/superlink/utils.py +9 -2
- flwr/server/utils/validator.py +2 -2
- flwr/serverapp/__init__.py +15 -0
- flwr/simulation/app.py +25 -0
- flwr/simulation/run_simulation.py +17 -0
- flwr/supercore/__init__.py +15 -0
- flwr/{server/superlink → supercore}/ffs/__init__.py +2 -0
- flwr/{server/superlink → supercore}/ffs/disk_ffs.py +1 -1
- flwr/supercore/grpc_health/__init__.py +22 -0
- flwr/supercore/grpc_health/simple_health_servicer.py +38 -0
- flwr/supercore/license_plugin/__init__.py +22 -0
- flwr/supercore/license_plugin/license_plugin.py +26 -0
- flwr/supercore/object_store/__init__.py +24 -0
- flwr/supercore/object_store/in_memory_object_store.py +229 -0
- flwr/supercore/object_store/object_store.py +170 -0
- flwr/supercore/object_store/object_store_factory.py +44 -0
- flwr/supercore/object_store/utils.py +43 -0
- flwr/supercore/scheduler/__init__.py +22 -0
- flwr/supercore/scheduler/plugin.py +71 -0
- flwr/{client/nodestate/nodestate.py → supercore/utils.py} +14 -13
- flwr/superexec/deployment.py +7 -4
- flwr/superexec/exec_event_log_interceptor.py +8 -4
- flwr/superexec/exec_grpc.py +25 -5
- flwr/superexec/exec_license_interceptor.py +82 -0
- flwr/superexec/exec_servicer.py +135 -24
- flwr/superexec/exec_user_auth_interceptor.py +45 -8
- flwr/superexec/executor.py +5 -1
- flwr/superexec/simulation.py +8 -3
- flwr/superlink/__init__.py +15 -0
- flwr/{client/supernode → supernode}/__init__.py +0 -7
- flwr/supernode/cli/__init__.py +24 -0
- flwr/{client/supernode/app.py → supernode/cli/flower_supernode.py} +3 -19
- flwr/supernode/cli/flwr_clientapp.py +88 -0
- flwr/supernode/nodestate/in_memory_nodestate.py +199 -0
- flwr/supernode/nodestate/nodestate.py +227 -0
- flwr/supernode/runtime/__init__.py +15 -0
- flwr/{client/clientapp/app.py → supernode/runtime/run_clientapp.py} +135 -89
- flwr/supernode/scheduler/__init__.py +22 -0
- flwr/supernode/scheduler/simple_clientapp_scheduler_plugin.py +49 -0
- flwr/supernode/servicer/__init__.py +15 -0
- flwr/supernode/servicer/clientappio/__init__.py +22 -0
- flwr/supernode/servicer/clientappio/clientappio_servicer.py +303 -0
- flwr/supernode/start_client_internal.py +589 -0
- {flwr-1.18.0.dist-info → flwr-1.20.0.dist-info}/METADATA +6 -4
- {flwr-1.18.0.dist-info → flwr-1.20.0.dist-info}/RECORD +171 -123
- {flwr-1.18.0.dist-info → flwr-1.20.0.dist-info}/WHEEL +1 -1
- {flwr-1.18.0.dist-info → flwr-1.20.0.dist-info}/entry_points.txt +2 -2
- flwr/client/clientapp/clientappio_servicer.py +0 -244
- flwr/client/heartbeat.py +0 -74
- flwr/client/nodestate/in_memory_nodestate.py +0 -38
- /flwr/{client → compat/client}/grpc_client/__init__.py +0 -0
- /flwr/{client → compat/client}/grpc_client/connection.py +0 -0
- /flwr/{server/superlink → supercore}/ffs/ffs.py +0 -0
- /flwr/{server/superlink → supercore}/ffs/ffs_factory.py +0 -0
- /flwr/{client → supernode}/nodestate/__init__.py +0 -0
- /flwr/{client → supernode}/nodestate/nodestate_factory.py +0 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# Copyright 2025 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""ClientAppIo API servicer."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from logging import DEBUG, ERROR
|
|
19
|
+
from typing import cast
|
|
20
|
+
|
|
21
|
+
import grpc
|
|
22
|
+
|
|
23
|
+
from flwr.common import Context
|
|
24
|
+
from flwr.common.inflatable import UnexpectedObjectContentError
|
|
25
|
+
from flwr.common.logger import log
|
|
26
|
+
from flwr.common.serde import (
|
|
27
|
+
context_from_proto,
|
|
28
|
+
context_to_proto,
|
|
29
|
+
fab_to_proto,
|
|
30
|
+
message_from_proto,
|
|
31
|
+
message_to_proto,
|
|
32
|
+
run_to_proto,
|
|
33
|
+
)
|
|
34
|
+
from flwr.common.typing import Fab, Run
|
|
35
|
+
|
|
36
|
+
# pylint: disable=E0611
|
|
37
|
+
from flwr.proto import clientappio_pb2_grpc
|
|
38
|
+
from flwr.proto.appio_pb2 import ( # pylint: disable=E0401
|
|
39
|
+
PullAppInputsRequest,
|
|
40
|
+
PullAppInputsResponse,
|
|
41
|
+
PullAppMessagesRequest,
|
|
42
|
+
PullAppMessagesResponse,
|
|
43
|
+
PushAppMessagesRequest,
|
|
44
|
+
PushAppMessagesResponse,
|
|
45
|
+
PushAppOutputsRequest,
|
|
46
|
+
PushAppOutputsResponse,
|
|
47
|
+
)
|
|
48
|
+
from flwr.proto.clientappio_pb2 import ( # pylint: disable=E0401
|
|
49
|
+
GetRunIdsWithPendingMessagesRequest,
|
|
50
|
+
GetRunIdsWithPendingMessagesResponse,
|
|
51
|
+
RequestTokenRequest,
|
|
52
|
+
RequestTokenResponse,
|
|
53
|
+
)
|
|
54
|
+
from flwr.proto.message_pb2 import (
|
|
55
|
+
ConfirmMessageReceivedRequest,
|
|
56
|
+
ConfirmMessageReceivedResponse,
|
|
57
|
+
PullObjectRequest,
|
|
58
|
+
PullObjectResponse,
|
|
59
|
+
PushObjectRequest,
|
|
60
|
+
PushObjectResponse,
|
|
61
|
+
)
|
|
62
|
+
from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
|
|
63
|
+
|
|
64
|
+
# pylint: disable=E0601
|
|
65
|
+
from flwr.supercore.ffs import FfsFactory
|
|
66
|
+
from flwr.supercore.object_store import NoObjectInStoreError, ObjectStoreFactory
|
|
67
|
+
from flwr.supercore.object_store.utils import store_mapping_and_register_objects
|
|
68
|
+
from flwr.supernode.nodestate import NodeStateFactory
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# pylint: disable=C0103,W0613,W0201
|
|
72
|
+
class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
|
|
73
|
+
"""ClientAppIo API servicer."""
|
|
74
|
+
|
|
75
|
+
def __init__(
|
|
76
|
+
self,
|
|
77
|
+
state_factory: NodeStateFactory,
|
|
78
|
+
ffs_factory: FfsFactory,
|
|
79
|
+
objectstore_factory: ObjectStoreFactory,
|
|
80
|
+
) -> None:
|
|
81
|
+
self.state_factory = state_factory
|
|
82
|
+
self.ffs_factory = ffs_factory
|
|
83
|
+
self.objectstore_factory = objectstore_factory
|
|
84
|
+
|
|
85
|
+
def GetRunIdsWithPendingMessages(
|
|
86
|
+
self,
|
|
87
|
+
request: GetRunIdsWithPendingMessagesRequest,
|
|
88
|
+
context: grpc.ServicerContext,
|
|
89
|
+
) -> GetRunIdsWithPendingMessagesResponse:
|
|
90
|
+
"""Get run IDs with pending messages."""
|
|
91
|
+
log(DEBUG, "ClientAppIo.GetRunIdsWithPendingMessages")
|
|
92
|
+
|
|
93
|
+
# Initialize state connection
|
|
94
|
+
state = self.state_factory.state()
|
|
95
|
+
|
|
96
|
+
# Get run IDs with pending messages
|
|
97
|
+
run_ids = state.get_run_ids_with_pending_messages()
|
|
98
|
+
|
|
99
|
+
# Return run IDs
|
|
100
|
+
return GetRunIdsWithPendingMessagesResponse(run_ids=run_ids)
|
|
101
|
+
|
|
102
|
+
def RequestToken(
|
|
103
|
+
self, request: RequestTokenRequest, context: grpc.ServicerContext
|
|
104
|
+
) -> RequestTokenResponse:
|
|
105
|
+
"""Request token."""
|
|
106
|
+
log(DEBUG, "ClientAppIo.RequestToken")
|
|
107
|
+
|
|
108
|
+
# Initialize state connection
|
|
109
|
+
state = self.state_factory.state()
|
|
110
|
+
|
|
111
|
+
# Attempt to create a token for the provided run ID
|
|
112
|
+
try:
|
|
113
|
+
token = state.create_token(request.run_id)
|
|
114
|
+
except ValueError:
|
|
115
|
+
# Return an empty token if A token already exists for this run ID,
|
|
116
|
+
# indicating the run is in progress
|
|
117
|
+
return RequestTokenResponse(token="")
|
|
118
|
+
|
|
119
|
+
# Return the token
|
|
120
|
+
return RequestTokenResponse(token=token)
|
|
121
|
+
|
|
122
|
+
def GetRun(
|
|
123
|
+
self, request: GetRunRequest, context: grpc.ServicerContext
|
|
124
|
+
) -> GetRunResponse:
|
|
125
|
+
"""Get run information."""
|
|
126
|
+
log(DEBUG, "ClientAppIo.GetRun")
|
|
127
|
+
|
|
128
|
+
# Initialize state connection
|
|
129
|
+
state = self.state_factory.state()
|
|
130
|
+
|
|
131
|
+
# Retrieve run information
|
|
132
|
+
run = state.get_run(request.run_id)
|
|
133
|
+
|
|
134
|
+
if run is None:
|
|
135
|
+
return GetRunResponse()
|
|
136
|
+
|
|
137
|
+
return GetRunResponse(run=run_to_proto(run))
|
|
138
|
+
|
|
139
|
+
def PullClientAppInputs(
|
|
140
|
+
self, request: PullAppInputsRequest, context: grpc.ServicerContext
|
|
141
|
+
) -> PullAppInputsResponse:
|
|
142
|
+
"""Pull Message, Context, and Run."""
|
|
143
|
+
log(DEBUG, "ClientAppIo.PullClientAppInputs")
|
|
144
|
+
|
|
145
|
+
# Initialize state and ffs connection
|
|
146
|
+
state = self.state_factory.state()
|
|
147
|
+
ffs = self.ffs_factory.ffs()
|
|
148
|
+
|
|
149
|
+
# Validate the token
|
|
150
|
+
run_id = state.get_run_id_by_token(request.token)
|
|
151
|
+
if run_id is None or not state.verify_token(run_id, request.token):
|
|
152
|
+
context.abort(
|
|
153
|
+
grpc.StatusCode.PERMISSION_DENIED,
|
|
154
|
+
"Invalid token.",
|
|
155
|
+
)
|
|
156
|
+
raise RuntimeError("This line should never be reached.")
|
|
157
|
+
|
|
158
|
+
# Retrieve context, run and fab for this run
|
|
159
|
+
context = cast(Context, state.get_context(run_id))
|
|
160
|
+
run = cast(Run, state.get_run(run_id))
|
|
161
|
+
fab = Fab(run.fab_hash, ffs.get(run.fab_hash)[0]) # type: ignore
|
|
162
|
+
|
|
163
|
+
return PullAppInputsResponse(
|
|
164
|
+
context=context_to_proto(context),
|
|
165
|
+
run=run_to_proto(run),
|
|
166
|
+
fab=fab_to_proto(fab),
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
def PushClientAppOutputs(
|
|
170
|
+
self, request: PushAppOutputsRequest, context: grpc.ServicerContext
|
|
171
|
+
) -> PushAppOutputsResponse:
|
|
172
|
+
"""Push Message and Context."""
|
|
173
|
+
log(DEBUG, "ClientAppIo.PushClientAppOutputs")
|
|
174
|
+
|
|
175
|
+
# Initialize state connection
|
|
176
|
+
state = self.state_factory.state()
|
|
177
|
+
|
|
178
|
+
# Validate the token
|
|
179
|
+
run_id = state.get_run_id_by_token(request.token)
|
|
180
|
+
if run_id is None or not state.verify_token(run_id, request.token):
|
|
181
|
+
context.abort(
|
|
182
|
+
grpc.StatusCode.PERMISSION_DENIED,
|
|
183
|
+
"Invalid token.",
|
|
184
|
+
)
|
|
185
|
+
raise RuntimeError("This line should never be reached.")
|
|
186
|
+
|
|
187
|
+
# Save the context to the state
|
|
188
|
+
state.store_context(context_from_proto(request.context))
|
|
189
|
+
|
|
190
|
+
# Remove the token to make the run eligible for processing
|
|
191
|
+
# A run associated with a token cannot be handled until its token is cleared
|
|
192
|
+
state.delete_token(run_id)
|
|
193
|
+
|
|
194
|
+
return PushAppOutputsResponse()
|
|
195
|
+
|
|
196
|
+
def PullMessage(
|
|
197
|
+
self, request: PullAppMessagesRequest, context: grpc.ServicerContext
|
|
198
|
+
) -> PullAppMessagesResponse:
|
|
199
|
+
"""Pull one Message."""
|
|
200
|
+
# Initialize state and store connection
|
|
201
|
+
state = self.state_factory.state()
|
|
202
|
+
store = self.objectstore_factory.store()
|
|
203
|
+
|
|
204
|
+
# Validate the token
|
|
205
|
+
run_id = state.get_run_id_by_token(request.token)
|
|
206
|
+
if run_id is None or not state.verify_token(run_id, request.token):
|
|
207
|
+
context.abort(
|
|
208
|
+
grpc.StatusCode.PERMISSION_DENIED,
|
|
209
|
+
"Invalid token.",
|
|
210
|
+
)
|
|
211
|
+
raise RuntimeError("This line should never be reached.")
|
|
212
|
+
|
|
213
|
+
# Retrieve message for this run
|
|
214
|
+
message = state.get_messages(run_ids=[run_id], is_reply=False)[0]
|
|
215
|
+
|
|
216
|
+
# Retrieve the object tree for the message
|
|
217
|
+
object_tree = store.get_object_tree(message.metadata.message_id)
|
|
218
|
+
|
|
219
|
+
return PullAppMessagesResponse(
|
|
220
|
+
messages_list=[message_to_proto(message)],
|
|
221
|
+
message_object_trees=[object_tree],
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
def PushMessage(
|
|
225
|
+
self, request: PushAppMessagesRequest, context: grpc.ServicerContext
|
|
226
|
+
) -> PushAppMessagesResponse:
|
|
227
|
+
"""Push one Message."""
|
|
228
|
+
# Initialize state and store connection
|
|
229
|
+
state = self.state_factory.state()
|
|
230
|
+
store = self.objectstore_factory.store()
|
|
231
|
+
|
|
232
|
+
# Validate the token
|
|
233
|
+
run_id = state.get_run_id_by_token(request.token)
|
|
234
|
+
if run_id is None or not state.verify_token(run_id, request.token):
|
|
235
|
+
context.abort(
|
|
236
|
+
grpc.StatusCode.PERMISSION_DENIED,
|
|
237
|
+
"Invalid token.",
|
|
238
|
+
)
|
|
239
|
+
raise RuntimeError("This line should never be reached.")
|
|
240
|
+
|
|
241
|
+
# Save the message to the state
|
|
242
|
+
state.store_message(message_from_proto(request.messages_list[0]))
|
|
243
|
+
|
|
244
|
+
# Store Message object to descendants mapping and preregister objects
|
|
245
|
+
objects_to_push = store_mapping_and_register_objects(store, request=request)
|
|
246
|
+
|
|
247
|
+
return PushAppMessagesResponse(objects_to_push=objects_to_push)
|
|
248
|
+
|
|
249
|
+
def PushObject(
|
|
250
|
+
self, request: PushObjectRequest, context: grpc.ServicerContext
|
|
251
|
+
) -> PushObjectResponse:
|
|
252
|
+
"""Push an object to the ObjectStore."""
|
|
253
|
+
log(DEBUG, "ServerAppIoServicer.PushObject")
|
|
254
|
+
|
|
255
|
+
# Init state and store
|
|
256
|
+
store = self.objectstore_factory.store()
|
|
257
|
+
|
|
258
|
+
# Insert in store
|
|
259
|
+
stored = False
|
|
260
|
+
try:
|
|
261
|
+
store.put(request.object_id, request.object_content)
|
|
262
|
+
stored = True
|
|
263
|
+
except (NoObjectInStoreError, ValueError) as e:
|
|
264
|
+
log(ERROR, str(e))
|
|
265
|
+
except UnexpectedObjectContentError as e:
|
|
266
|
+
# Object content is not valid
|
|
267
|
+
context.abort(grpc.StatusCode.FAILED_PRECONDITION, str(e))
|
|
268
|
+
|
|
269
|
+
return PushObjectResponse(stored=stored)
|
|
270
|
+
|
|
271
|
+
def PullObject(
|
|
272
|
+
self, request: PullObjectRequest, context: grpc.ServicerContext
|
|
273
|
+
) -> PullObjectResponse:
|
|
274
|
+
"""Pull an object from the ObjectStore."""
|
|
275
|
+
log(DEBUG, "ServerAppIoServicer.PullObject")
|
|
276
|
+
|
|
277
|
+
# Init state and store
|
|
278
|
+
store = self.objectstore_factory.store()
|
|
279
|
+
|
|
280
|
+
# Fetch from store
|
|
281
|
+
content = store.get(request.object_id)
|
|
282
|
+
if content is not None:
|
|
283
|
+
object_available = content != b""
|
|
284
|
+
return PullObjectResponse(
|
|
285
|
+
object_found=True,
|
|
286
|
+
object_available=object_available,
|
|
287
|
+
object_content=content,
|
|
288
|
+
)
|
|
289
|
+
return PullObjectResponse(object_found=False, object_available=False)
|
|
290
|
+
|
|
291
|
+
def ConfirmMessageReceived(
|
|
292
|
+
self, request: ConfirmMessageReceivedRequest, context: grpc.ServicerContext
|
|
293
|
+
) -> ConfirmMessageReceivedResponse:
|
|
294
|
+
"""Confirm message received."""
|
|
295
|
+
log(DEBUG, "ServerAppIoServicer.ConfirmMessageReceived")
|
|
296
|
+
|
|
297
|
+
# Init state and store
|
|
298
|
+
store = self.objectstore_factory.store()
|
|
299
|
+
|
|
300
|
+
# Delete the message object
|
|
301
|
+
store.delete(request.message_object_id)
|
|
302
|
+
|
|
303
|
+
return ConfirmMessageReceivedResponse()
|