feat: opt-in node fanout for apiv2 save - #99
Open
shenaba wants to merge 1 commit into
Open
Conversation
apiv2 save now honours a `sync` form value: without it a client/inbound change converges through the hourly reconcile, with it the nodes are pushed immediately, the way the web UI always has. Malformed values are rejected rather than silently degrading to "no fanout". Loop safety was never this flag's job — expectedClients' node_id scoping is what keeps a pushed client out of every outgoing set — so the comments claiming otherwise are corrected. Reviewing that surface turned up several cluster bugs, fixed here: - clientDiffers compared a config the node's clients projection never sent, so every @cluster client was re-pushed every round, each push appending a credential-bearing changes row that nothing prunes. Config now ships only to the reconcile read (full=1), keeping it off the websocket payload and out of browser sessions, and is compared only when both sides carry one — which also covers mixed-version clusters and configless clients. - A node push omits the traffic counters, and Save wrote them back as zero, wiping the node's history. They are preserved unless the request actually carries them, which is how the per-client reset expresses itself: the drawer sends them only after Reset is clicked, so an edit from a drawer left open no longer rolls back everything the stats job recorded. - editbulk submits the list projection, whose omitted columns were written back as zeros, silently switching off periodic auto-reset. - Node-owned links were taken from the request payload, so a tab loaded before the last reconcile stripped every cluster route from a client's subscription. They now come from the stored row, scoped to the replica inbounds the client still references so revoking access takes effect even while that node is offline, and the drawer renders them read-only. - Resetting traffic re-enables depleted clients but never told the nodes, leaving paid-up users rejected for up to an hour. - The "[node] " link marker had four independent encodings; it now has one, inbound deletion strips the prefixed form, and node names may no longer contain brackets that would make two nodes' prefixes overlap. - ConfigService.Save's unknown-object branch left the named err nil, so the deferred commit, hub notify and core start ran for a failed request. The hostname baked into generated links and the advertised subscription URI is now resolved in one place, preferring the configured web domain and normalising it the same way a request Host is. In the client drawer, links are no longer truncated and a copy-all button hands the whole set over for bulk import into a proxy client.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
POST <panel path>apiv2/savenow honours asyncform value. Without it aclient/inbound change converges through the hourly reconcile; with it the nodes
are pushed immediately, the way the web UI always has. Malformed values are
rejected rather than silently degrading to "no fanout".
Loop safety was never this flag's job —
expectedClients'node_idscoping iswhat keeps a pushed client out of every outgoing set — so the comments claiming
otherwise are corrected.
Cluster bugs fixed along the way
Reviewing that surface turned up a number of pre-existing problems:
@clusterclient was re-pushed every reconcile round.clientDifferscompared a
configthe node's clients projection never sent, so the comparealways failed. Each spurious push appended a credential-bearing
changesrow,and nothing prunes that table. Config now ships only to the reconcile read
(
full=1) — keeping it off the websocket payload and out of browser sessions —and is compared only when both sides carry one, which also covers
mixed-version clusters and configless clients.
Savewrote them back as zero. They are now preserved unless the requestactually carries them, which is how the per-client reset expresses itself: the
drawer sends them only after Reset is clicked, so an edit from a drawer left
open no longer rolls back what the stats job recorded meanwhile.
editbulksilently switched off periodic auto-reset, writing the listprojection's omitted columns back as zeros.
Node-owned links were taken from the request payload; they now come from the
stored row, scoped to the replica inbounds the client still references so
revoking access takes effect even while that node is offline. The drawer
renders them read-only.
re-enables depleted clients but never told the nodes.
[node]link marker had four independent encodings. Now one; inbounddeletion strips the prefixed form, and node names may no longer contain
brackets that would make two nodes' prefixes overlap.
ConfigService.Save's unknown-object branch left the namederrnil, sothe deferred commit, hub notify and core start ran for a failed request.
The hostname baked into generated links and the advertised subscription URI is
now resolved in one place, preferring the configured web domain and normalising
it the same way a request Host is.
UI
Links in the client drawer are no longer truncated, and a copy-all button hands
the whole set over for bulk import into a proxy client.
Verification
go vet, the full tagged build andvue-tscall pass. Functionally verified ona real panel:
up/downandrolls the totals correctly
apiv2/clientsomitsconfig,apiv2/clients?full=1includes itNo automated tests — the
apipackage has no test scaffolding today, which istracked separately.