PUT /panels/ carries a version and refuses a stale one with 409
The Panels dialog re-reads the list on 409. A panels.json without a version reads as 0.
This commit is contained in:
@@ -269,6 +269,8 @@ class PanelsPublic(BaseModel):
|
||||
"""
|
||||
|
||||
panels: list[PanelDef] = Field(default_factory=list)
|
||||
#: What a save of this list has to send back.
|
||||
version: int = 0
|
||||
#: Whatever this instance was told it is reachable at. The same setting
|
||||
#: the password-reset links are built from, so an instance that has it
|
||||
#: wrong has it wrong in both places.
|
||||
@@ -277,7 +279,9 @@ class PanelsPublic(BaseModel):
|
||||
|
||||
def _public(config: PanelsConfig) -> PanelsPublic:
|
||||
return PanelsPublic(
|
||||
panels=config.panels, frontend_host=settings.FRONTEND_HOST.rstrip("/")
|
||||
panels=config.panels,
|
||||
version=config.version,
|
||||
frontend_host=settings.FRONTEND_HOST.rstrip("/"),
|
||||
)
|
||||
|
||||
|
||||
@@ -298,6 +302,11 @@ async def save_panels(body: PanelsConfig) -> Any:
|
||||
A panel that disappears here takes its credential with it, so this is also
|
||||
how a device is unpaired along with its assignment. Re-pairing one screen
|
||||
and keeping the assignment is ``/{panel_id}/unpair`` below.
|
||||
|
||||
The body carries the ``version`` it was based on, and a save someone else
|
||||
has moved past is refused with 409, as a dashboard's is. Two clients each
|
||||
writing back the whole list would otherwise drop each other's panels, and
|
||||
a dropped panel revokes its screen at once.
|
||||
"""
|
||||
seen = set()
|
||||
for panel in body.panels:
|
||||
@@ -314,9 +323,19 @@ async def save_panels(body: PanelsConfig) -> Any:
|
||||
# saving an arrangement — and reading it in a separate step from
|
||||
# writing it is exactly how an unpair in between was undone.
|
||||
with edit_lock:
|
||||
stored = {p.id: p.nonce for p in read_config().panels}
|
||||
stored = read_config()
|
||||
if body.version != stored.version:
|
||||
raise HTTPException(
|
||||
status_code=409,
|
||||
detail={
|
||||
"message": "Someone else saved the panels first",
|
||||
"current_version": stored.version,
|
||||
},
|
||||
)
|
||||
nonces = {p.id: p.nonce for p in stored.panels}
|
||||
for panel in body.panels:
|
||||
panel.nonce = stored.get(panel.id, 0)
|
||||
panel.nonce = nonces.get(panel.id, 0)
|
||||
body.version = stored.version + 1
|
||||
write_config(body)
|
||||
|
||||
await run_in_threadpool(_save)
|
||||
|
||||
Reference in New Issue
Block a user