flux-config-shared 0.1.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.
- flux_config_shared/__init__.py +23 -0
- flux_config_shared/app_config.py +102 -0
- flux_config_shared/config_locations.py +46 -0
- flux_config_shared/daemon_state.py +163 -0
- flux_config_shared/delegate_config.py +112 -0
- flux_config_shared/log.py +124 -0
- flux_config_shared/models.py +48 -0
- flux_config_shared/protocol.py +402 -0
- flux_config_shared/user_config.py +660 -0
- flux_config_shared-0.1.0.dist-info/METADATA +40 -0
- flux_config_shared-0.1.0.dist-info/RECORD +12 -0
- flux_config_shared-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
"""JSON-RPC 2.0 protocol definitions for daemon/client communication."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from enum import Enum, auto
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel, Field
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class InstallState(Enum):
|
|
12
|
+
"""Overall installation state of the system."""
|
|
13
|
+
|
|
14
|
+
NEW = auto() # First-time installation
|
|
15
|
+
RESUMING = auto() # Resuming incomplete installation
|
|
16
|
+
COMPLETE = auto() # All tasks finished
|
|
17
|
+
CANCELLED = auto() # Installation was cancelled by user
|
|
18
|
+
SCHEMA_MIGRATION = auto() # Schema was updated, some tasks done
|
|
19
|
+
RECONFIGURING_NOW = auto() # User chose to reconfigure now
|
|
20
|
+
RECONFIGURING_LATER = auto() # User chose to reconfigure later
|
|
21
|
+
UNKNOWN = auto() # Initial state before loading from DB
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class MethodName(str, Enum):
|
|
25
|
+
"""RPC method names (Client → Daemon)."""
|
|
26
|
+
|
|
27
|
+
# Subscriptions (topic-based event streaming)
|
|
28
|
+
SUBSCRIBE = "subscribe"
|
|
29
|
+
UNSUBSCRIBE = "unsubscribe"
|
|
30
|
+
|
|
31
|
+
# Configuration
|
|
32
|
+
CONFIG_GET_USER = "config.get_user"
|
|
33
|
+
CONFIG_SET_USER = "config.set_user"
|
|
34
|
+
CONFIG_GET_INSTALLER = "config.get_installer"
|
|
35
|
+
CONFIG_GET_APP = "config.get_app"
|
|
36
|
+
CONFIG_UPDATE_APP = "config.update_app"
|
|
37
|
+
CONFIG_VALIDATE_PUBKEY = "config.validate_pubkey"
|
|
38
|
+
CONFIG_WRITE_FLUXD_GENERIC = "config.write_fluxd_generic"
|
|
39
|
+
CONFIG_CREATE_FLUXD = "config.create_fluxd"
|
|
40
|
+
CONFIG_REMOVE = "config.remove"
|
|
41
|
+
CONFIG_GET_SHAPING_POLICY = "config.get_shaping_policy"
|
|
42
|
+
|
|
43
|
+
# State Management
|
|
44
|
+
STATE_POPULATE = "state.populate"
|
|
45
|
+
STATE_GET_RECONFIGURE = "state.get_reconfigure"
|
|
46
|
+
STATE_CREATE_MARKER = "state.create_marker"
|
|
47
|
+
STATE_REMOVE_MARKER = "state.remove_marker"
|
|
48
|
+
STATE_MARKER_EXISTS = "state.marker_exists"
|
|
49
|
+
|
|
50
|
+
# Service Management
|
|
51
|
+
SERVICE_START = "service.start"
|
|
52
|
+
SERVICE_STOP = "service.stop"
|
|
53
|
+
SERVICE_RESTART = "service.restart"
|
|
54
|
+
SERVICE_ENABLE = "service.enable"
|
|
55
|
+
SERVICE_DISABLE = "service.disable"
|
|
56
|
+
SERVICE_GET_STATUS = "service.get_status"
|
|
57
|
+
SERVICE_LIST = "service.list"
|
|
58
|
+
SERVICE_SUBSCRIBE = "service.subscribe"
|
|
59
|
+
SERVICE_UNSUBSCRIBE = "service.unsubscribe"
|
|
60
|
+
|
|
61
|
+
# System
|
|
62
|
+
SYSTEM_REBOOT = "system.reboot"
|
|
63
|
+
SYSTEM_SHUTDOWN = "system.shutdown"
|
|
64
|
+
SYSTEM_FIRMWARE_REBOOT = "system.firmware_reboot"
|
|
65
|
+
SYSTEM_DAEMON_RELOAD = "system.daemon_reload"
|
|
66
|
+
SYSTEM_SYNC = "system.sync"
|
|
67
|
+
SYSTEM_DROP_CACHES = "system.drop_caches"
|
|
68
|
+
SYSTEM_GET_PUBLIC_IP = "system.get_public_ip"
|
|
69
|
+
SYSTEM_CHECK_UEFI = "system.check_uefi"
|
|
70
|
+
SYSTEM_CHECK_LUKS = "system.check_luks"
|
|
71
|
+
SYSTEM_CHECK_CONNECTIVITY = "system.check_connectivity"
|
|
72
|
+
SYSTEM_GET_LOCAL_IP = "system.get_local_ip"
|
|
73
|
+
|
|
74
|
+
# Firewall
|
|
75
|
+
FIREWALL_ADD_RULE = "firewall.add_rule"
|
|
76
|
+
FIREWALL_REMOVE_RULE = "firewall.remove_rule"
|
|
77
|
+
FIREWALL_GET_RULES = "firewall.get_rules"
|
|
78
|
+
|
|
79
|
+
# Installation
|
|
80
|
+
INSTALL_START = "install.start"
|
|
81
|
+
INSTALL_GET_STATE = "install.get_state"
|
|
82
|
+
INSTALL_ABORT = "install.abort"
|
|
83
|
+
INSTALL_CANCEL = "install.cancel"
|
|
84
|
+
|
|
85
|
+
# Reinstall (post-installation)
|
|
86
|
+
REINSTALL_START = "reinstall.start"
|
|
87
|
+
|
|
88
|
+
# FluxD
|
|
89
|
+
FLUXD_GET_STATUS = "fluxd.get_status"
|
|
90
|
+
FLUXD_GET_BLOCK_HEIGHT = "fluxd.get_block_height"
|
|
91
|
+
FLUXD_GET_BLOCK_HEIGHT_API = "fluxd.get_block_height_api"
|
|
92
|
+
FLUXD_GET_INFO = "fluxd.get_info"
|
|
93
|
+
FLUXD_CALL_RPC = "fluxd.call_rpc"
|
|
94
|
+
FLUXD_TEST_DBS = "fluxd.test_dbs"
|
|
95
|
+
FLUXD_GET_BLOCKHEIGHT_FROM_DB = "fluxd.get_blockheight_from_db"
|
|
96
|
+
FLUXD_GET_BLOCK_COUNT = "fluxd.get_block_count"
|
|
97
|
+
FLUXD_ZMQ_STATUS = "fluxd.zmq_status"
|
|
98
|
+
|
|
99
|
+
# FluxBenchD
|
|
100
|
+
FLUXBENCHD_GET_STATUS = "fluxbenchd.get_status"
|
|
101
|
+
FLUXBENCHD_GET_BENCHMARKS = "fluxbenchd.get_benchmarks"
|
|
102
|
+
FLUXBENCHD_CALL_RPC = "fluxbenchd.call_rpc"
|
|
103
|
+
|
|
104
|
+
# Delegate Node Starting
|
|
105
|
+
DELEGATE_CHECK_READINESS = "delegate.check_readiness"
|
|
106
|
+
DELEGATE_VALIDATE_PASSWORD = "delegate.validate_password"
|
|
107
|
+
DELEGATE_START_NODE = "delegate.start_node"
|
|
108
|
+
|
|
109
|
+
# Node Operations
|
|
110
|
+
NODE_CLONE_REPO = "node.clone_repo"
|
|
111
|
+
NODE_NPM_INSTALL = "node.npm_install"
|
|
112
|
+
NODE_DOWNLOAD_CHAIN = "node.download_chain"
|
|
113
|
+
NODE_VERIFY_CHAIN = "node.verify_chain"
|
|
114
|
+
NODE_FETCH_PARAMS = "node.fetch_params"
|
|
115
|
+
NODE_GET_CHAIN_PROGRESS = "node.get_chain_progress"
|
|
116
|
+
|
|
117
|
+
# Bootstrap Operations
|
|
118
|
+
BOOTSTRAP_GET_FASTEST_CDN = "bootstrap.get_fastest_cdn"
|
|
119
|
+
|
|
120
|
+
# Upgrade Operations
|
|
121
|
+
UPGRADE_CHECK = "upgrade.check"
|
|
122
|
+
UPGRADE_START = "upgrade.start"
|
|
123
|
+
UPGRADE_GET_STATE = "upgrade.get_state"
|
|
124
|
+
UPGRADE_DEFER_REBOOT = "upgrade.defer_reboot"
|
|
125
|
+
|
|
126
|
+
# Reconfiguration
|
|
127
|
+
RECONFIGURE_SET_MODE = "reconfigure.set_mode"
|
|
128
|
+
RECONFIGURE_GET_STATE = "reconfigure.get_state"
|
|
129
|
+
RECONFIGURE_SERVICES = "reconfigure.services"
|
|
130
|
+
RECONFIGURE_START = "reconfigure.start"
|
|
131
|
+
|
|
132
|
+
# Display / X11
|
|
133
|
+
DISPLAY_SET_RESOLUTION = "display.set_resolution"
|
|
134
|
+
DISPLAY_SET_DPMS = "display.set_dpms"
|
|
135
|
+
DISPLAY_GET_RESOLUTIONS = "display.get_resolutions"
|
|
136
|
+
|
|
137
|
+
# Web API / Webserver
|
|
138
|
+
WEB_GET_TOKEN = "web.get_token" # noqa: S105
|
|
139
|
+
WEB_CONFIGURE = "web.configure"
|
|
140
|
+
WEBSERVER_START = "webserver.start"
|
|
141
|
+
WEBSERVER_STOP = "webserver.stop"
|
|
142
|
+
WEBSERVER_GET_STATUS = "webserver.get_status"
|
|
143
|
+
|
|
144
|
+
# Tunnel Management
|
|
145
|
+
TUNNEL_START = "tunnel.start"
|
|
146
|
+
TUNNEL_STOP = "tunnel.stop"
|
|
147
|
+
TUNNEL_GET_STATUS = "tunnel.get_status"
|
|
148
|
+
|
|
149
|
+
# System Metrics
|
|
150
|
+
METRICS_GET_SYSTEM_LOAD = "metrics.get_system_load"
|
|
151
|
+
METRICS_GET_MEMORY = "metrics.get_memory"
|
|
152
|
+
METRICS_GET_DISK = "metrics.get_disk"
|
|
153
|
+
METRICS_GET_CPU = "metrics.get_cpu"
|
|
154
|
+
METRICS_GET_NETWORK = "metrics.get_network"
|
|
155
|
+
METRICS_GET_PROCESS_MEMORY = "metrics.get_process_memory"
|
|
156
|
+
|
|
157
|
+
# Logs
|
|
158
|
+
LOGS_GET_SERVICE = "logs.get_service"
|
|
159
|
+
LOGS_GET_JOURNAL = "logs.get_journal"
|
|
160
|
+
LOGS_GET_AVAILABLE_SERVICES = "logs.get_available_services"
|
|
161
|
+
|
|
162
|
+
# Filesystem
|
|
163
|
+
FILESYSTEM_CREATE_DIRECTORIES = "filesystem.create_directories"
|
|
164
|
+
FILESYSTEM_REMOVE_DIRECTORIES = "filesystem.remove_directories"
|
|
165
|
+
FILESYSTEM_HASH_FILE = "filesystem.hash_file"
|
|
166
|
+
|
|
167
|
+
# Task Management (async operations)
|
|
168
|
+
TASK_GET_STATUS = "task.get_status"
|
|
169
|
+
TASK_LIST = "task.list"
|
|
170
|
+
|
|
171
|
+
# Network Interface Management
|
|
172
|
+
NETWORK_GET_INTERFACES = "network.get_interfaces"
|
|
173
|
+
NETWORK_SET_STATIC_IP = "network.set_static_ip"
|
|
174
|
+
NETWORK_SET_DHCP = "network.set_dhcp"
|
|
175
|
+
NETWORK_SET_DISABLED = "network.set_disabled"
|
|
176
|
+
NETWORK_CREATE_VLAN = "network.create_vlan"
|
|
177
|
+
NETWORK_DELETE_VLAN = "network.delete_vlan"
|
|
178
|
+
NETWORK_RESTART_NETWORKD = "network.restart_networkd"
|
|
179
|
+
|
|
180
|
+
# Network DNS
|
|
181
|
+
NETWORK_GET_DNS = "network.get_dns"
|
|
182
|
+
NETWORK_TEST_DNS = "network.test_dns"
|
|
183
|
+
|
|
184
|
+
# Network Routing
|
|
185
|
+
NETWORK_GET_ROUTES = "network.get_routes"
|
|
186
|
+
NETWORK_TEST_CONNECTIVITY = "network.test_connectivity"
|
|
187
|
+
|
|
188
|
+
# Network UPnP
|
|
189
|
+
NETWORK_UPNP_GET_STATUS = "network.upnp.get_status"
|
|
190
|
+
NETWORK_UPNP_GET_MAPPINGS = "network.upnp.get_mappings"
|
|
191
|
+
NETWORK_UPNP_ADD_MAPPING = "network.upnp.add_mapping"
|
|
192
|
+
NETWORK_UPNP_REMOVE_MAPPING = "network.upnp.remove_mapping"
|
|
193
|
+
|
|
194
|
+
# Network Traffic Shaping
|
|
195
|
+
NETWORK_SHAPING_GET_POLICY = "network.shaping.get_policy"
|
|
196
|
+
NETWORK_SHAPING_SET_POLICY = "network.shaping.set_policy"
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class EventType(str, Enum):
|
|
200
|
+
"""Event types (Daemon → Client)."""
|
|
201
|
+
|
|
202
|
+
# Service State
|
|
203
|
+
SERVICE_STATE_CHANGED = "service.state_changed"
|
|
204
|
+
SERVICE_STATES_READY = "service.states_ready"
|
|
205
|
+
SERVICE_STARTED = "service.started"
|
|
206
|
+
SERVICE_STOPPED = "service.stopped"
|
|
207
|
+
|
|
208
|
+
# Installation Progress
|
|
209
|
+
INSTALL_TASK_STARTED = "install.task_started"
|
|
210
|
+
INSTALL_TASK_COMPLETED = "install.task_completed"
|
|
211
|
+
INSTALL_TASK_CANCELLED = "install.task_cancelled"
|
|
212
|
+
INSTALL_TASK_FAILED = "install.task_failed"
|
|
213
|
+
INSTALL_PROGRESS = "install.progress"
|
|
214
|
+
INSTALL_STATE_CHANGED = "install.state_changed"
|
|
215
|
+
|
|
216
|
+
# Download Progress (chain, params)
|
|
217
|
+
DOWNLOAD_PROGRESS = "download.progress"
|
|
218
|
+
DOWNLOAD_COMPLETED = "download.completed"
|
|
219
|
+
DOWNLOAD_FAILED = "download.failed"
|
|
220
|
+
|
|
221
|
+
# Upgrade Events
|
|
222
|
+
UPGRADE_STARTED = "upgrade.started"
|
|
223
|
+
UPGRADE_IN_PROGRESS = "upgrade.in_progress" # Alias for UPGRADE_STARTED
|
|
224
|
+
UPGRADE_AVAILABLE = "upgrade.available"
|
|
225
|
+
UPGRADE_PROGRESS = "upgrade.progress"
|
|
226
|
+
UPGRADE_PROPERTY_CHANGED = "upgrade.property_changed"
|
|
227
|
+
UPGRADE_COMPLETED = "upgrade.completed"
|
|
228
|
+
UPGRADE_FAILED = "upgrade.failed"
|
|
229
|
+
|
|
230
|
+
# System Events
|
|
231
|
+
SYSTEM_CONNECTIVITY = "system.connectivity"
|
|
232
|
+
SYSTEM_PUBLIC_IP = "system.public_ip"
|
|
233
|
+
SYSTEM_ERROR = "system.error"
|
|
234
|
+
SYSTEM_METRICS_UPDATE = "system.metrics_update" # Periodic metrics (every 5s)
|
|
235
|
+
NETWORK_CONFIG_REQUIRED = "network.config_required"
|
|
236
|
+
INSUFFICIENT_SPACE = "system.insufficient_space"
|
|
237
|
+
|
|
238
|
+
# Network Events
|
|
239
|
+
NETWORK_INTERFACE_CHANGED = "network.interface_changed"
|
|
240
|
+
NETWORK_ROUTES_CHANGED = "network.routes_changed"
|
|
241
|
+
NETWORK_DNS_CHANGED = "network.dns_changed"
|
|
242
|
+
NETWORK_UPNP_STATUS_CHANGED = "network.upnp_status_changed"
|
|
243
|
+
|
|
244
|
+
# Network Monitoring Events (subscription-triggered)
|
|
245
|
+
CONNECTIVITY_UPDATE = "network.connectivity_update"
|
|
246
|
+
DNS_RESOLUTION_UPDATE = "network.dns_resolution_update"
|
|
247
|
+
|
|
248
|
+
# Fluxd Events
|
|
249
|
+
FLUXD_RPC_ONLINE = "fluxd.rpc_online"
|
|
250
|
+
FLUXD_RPC_OFFLINE = "fluxd.rpc_offline"
|
|
251
|
+
FLUXD_BLOCK_HEIGHT = "fluxd.block_height"
|
|
252
|
+
FLUXD_ZMQ_CONNECTED = "fluxd.zmq_connected"
|
|
253
|
+
FLUXD_ZMQ_DISCONNECTED = "fluxd.zmq_disconnected"
|
|
254
|
+
FLUXD_ZMQ_NEW_BLOCK = "fluxd.zmq_new_block"
|
|
255
|
+
FLUXD_STATUS_CHANGED = "fluxd.status_changed"
|
|
256
|
+
FLUXBENCHD_STATUS_CHANGED = "fluxbenchd.status_changed"
|
|
257
|
+
|
|
258
|
+
# Web Configuration
|
|
259
|
+
WEBSERVER_STARTED = "webserver.started"
|
|
260
|
+
WEBSERVER_STOPPED = "webserver.stopped"
|
|
261
|
+
|
|
262
|
+
# Tunnel Events
|
|
263
|
+
TUNNEL_CONNECTING = "tunnel.connecting"
|
|
264
|
+
TUNNEL_STARTED = "tunnel.started"
|
|
265
|
+
TUNNEL_STOPPED = "tunnel.stopped"
|
|
266
|
+
TUNNEL_ERROR = "tunnel.error"
|
|
267
|
+
|
|
268
|
+
# Log/Activity Messages
|
|
269
|
+
LOG_MESSAGE = "log.message"
|
|
270
|
+
|
|
271
|
+
# State Synchronization
|
|
272
|
+
STATE_UPDATE = "state.update" # Unified state update event
|
|
273
|
+
INITIAL_STATE = "state.initial" # Complete state sent to new clients
|
|
274
|
+
|
|
275
|
+
# Async Task Events (for long-running operations)
|
|
276
|
+
TASK_STARTED = "task.started"
|
|
277
|
+
TASK_PROGRESS = "task.progress"
|
|
278
|
+
TASK_COMPLETED = "task.completed"
|
|
279
|
+
TASK_FAILED = "task.failed"
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class RPCErrorCode(int, Enum):
|
|
283
|
+
"""JSON-RPC 2.0 error codes."""
|
|
284
|
+
|
|
285
|
+
PARSE_ERROR = -32700
|
|
286
|
+
INVALID_REQUEST = -32600
|
|
287
|
+
METHOD_NOT_FOUND = -32601
|
|
288
|
+
INVALID_PARAMS = -32602
|
|
289
|
+
INTERNAL_ERROR = -32603
|
|
290
|
+
|
|
291
|
+
# Custom error codes
|
|
292
|
+
UNAUTHORIZED = -32000
|
|
293
|
+
SERVICE_NOT_FOUND = -32001
|
|
294
|
+
INSTALLATION_IN_PROGRESS = -32002
|
|
295
|
+
INSTALLATION_FAILED = -32003
|
|
296
|
+
PRIVILEGE_ERROR = -32004
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
class JsonRpcRequest(BaseModel):
|
|
300
|
+
"""JSON-RPC 2.0 request message."""
|
|
301
|
+
|
|
302
|
+
jsonrpc: str = Field(default="2.0", description="JSON-RPC version")
|
|
303
|
+
method: str = Field(description="Method name")
|
|
304
|
+
params: dict[str, Any] | list[Any] | None = Field(default=None, description="Method parameters")
|
|
305
|
+
id: str | int | None = Field(default=None, description="Request ID")
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
class JsonRpcError(BaseModel):
|
|
309
|
+
"""JSON-RPC 2.0 error object."""
|
|
310
|
+
|
|
311
|
+
code: int = Field(description="Error code")
|
|
312
|
+
message: str = Field(description="Error message")
|
|
313
|
+
data: Any | None = Field(default=None, description="Additional error data")
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
class JsonRpcResponse(BaseModel):
|
|
317
|
+
"""JSON-RPC 2.0 response message."""
|
|
318
|
+
|
|
319
|
+
jsonrpc: str = Field(default="2.0", description="JSON-RPC version")
|
|
320
|
+
result: Any | None = Field(default=None, description="Method result")
|
|
321
|
+
error: JsonRpcError | None = Field(default=None, description="Error object")
|
|
322
|
+
id: str | int | None = Field(default=None, description="Request ID")
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
class Event(BaseModel):
|
|
326
|
+
"""Event message (Daemon → Client)."""
|
|
327
|
+
|
|
328
|
+
type: str = Field(description="Event type")
|
|
329
|
+
data: dict[str, Any] = Field(description="Event data")
|
|
330
|
+
timestamp: float = Field(description="Event timestamp (Unix time)")
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
# --- Data Models ---
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
class ServiceStatusData(BaseModel):
|
|
337
|
+
"""Service status data."""
|
|
338
|
+
|
|
339
|
+
name: str
|
|
340
|
+
active: bool
|
|
341
|
+
running: bool
|
|
342
|
+
enabled: bool
|
|
343
|
+
pid: int | None = None
|
|
344
|
+
error: str | None = None
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
class InstallStateData(BaseModel):
|
|
348
|
+
"""Installation state data."""
|
|
349
|
+
|
|
350
|
+
in_progress: bool
|
|
351
|
+
current_task: str | None = None
|
|
352
|
+
completed_tasks: list[str]
|
|
353
|
+
failed_task: str | None = None
|
|
354
|
+
error: str | None = None
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
class UpgradeStateData(BaseModel):
|
|
358
|
+
"""Upgrade state data - maps to D-Bus FluxUpgrade1 properties."""
|
|
359
|
+
|
|
360
|
+
validating: bool = False
|
|
361
|
+
available: bool = False
|
|
362
|
+
in_progress: bool = False
|
|
363
|
+
bytes_complete: int = 0
|
|
364
|
+
bytes_total: int = 0
|
|
365
|
+
start_time: float = 0.0
|
|
366
|
+
finish_time: float = 0.0
|
|
367
|
+
attempts: int = 0
|
|
368
|
+
reboot_deferred: bool = False
|
|
369
|
+
reboot_timer: int = 0
|
|
370
|
+
current_version: str | None = None
|
|
371
|
+
new_version: str | None = None
|
|
372
|
+
|
|
373
|
+
@property
|
|
374
|
+
def in_flight(self) -> bool:
|
|
375
|
+
"""Check if any upgrade activity is in progress."""
|
|
376
|
+
return self.validating or self.available or self.in_progress
|
|
377
|
+
|
|
378
|
+
@property
|
|
379
|
+
def progress(self) -> float | None:
|
|
380
|
+
"""Calculate progress as a percentage (0.0 to 1.0)."""
|
|
381
|
+
if self.bytes_total > 0:
|
|
382
|
+
return self.bytes_complete / self.bytes_total
|
|
383
|
+
return None
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
class DownloadProgressData(BaseModel):
|
|
387
|
+
"""Download progress data."""
|
|
388
|
+
|
|
389
|
+
file: str
|
|
390
|
+
bytes_downloaded: int
|
|
391
|
+
total_bytes: int | None = None
|
|
392
|
+
percent: float | None = None
|
|
393
|
+
speed_mbps: float | None = None
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
class FluxdStatusData(BaseModel):
|
|
397
|
+
"""Fluxd RPC status data."""
|
|
398
|
+
|
|
399
|
+
online: bool
|
|
400
|
+
block_height: int | None = None
|
|
401
|
+
connections: int | None = None
|
|
402
|
+
synced: bool | None = None
|