Repository navigation
Commit 367aa93
LuckPerms bridge for the website staff panel (#32)
* Add LuckPerms bridge config and site client
Adds the luckperms-bridge config section (publish, apply, poll-seconds,
snapshot-seconds; off by default) and a client for the staff panel's
LuckPerms plugin routes: snapshot upload, unchanged-snapshot check,
change polling and result posting. Results and checks carry the
revision the site uses to order them. Snapshots go through the
gateway's longer upload timeout because they can be about a megabyte.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Bridge LuckPerms and the staff panel
LuckPermsBridge runs one daemon worker thread (TFMCWeb-LuckPerms) that
publishes LuckPerms snapshots and, on the one server set to apply,
polls staff-queued changes, so a snapshot never predates an applied
change. Unchanged snapshots are only confirmed by hash; a full upload
follows when the site asks for one or the data changed. Results the
site did not take are kept and posted again on later ticks. Snapshots
and results carry a strictly increasing revision. Failures are logged
once per outage with fixed messages.
LuckPermsBridgeStore, loaded by class name so TFMCWeb still runs
without LuckPerms, builds sorted snapshots (groups, tracks, every user
with stored nodes, cached player names) and applies changes: every
precondition is checked in op order against a staged copy of the
holder first, then the live holder is changed and saved once. A failed
mutation or save reloads loaded holders from storage. Each applied
change pushes a messaging update and is written to the LuckPerms
action log. The plugin starts, reloads and stops the bridge, and
/web status reports it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Document the LuckPerms bridge
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Refuse admin changes to staff players and staff groups
A change may carry a guard listing the groups a website admin (not
root) may manage. When it does, the bridge checks live LuckPerms data
before mutating anything: the player must hold no positive inheritance
node, in any context or expiry, for a group outside that list
(target_is_staff), and every group the change adds must, with all the
groups it inherits transitively, stay inside the list (root_only).
Names compare case-insensitively, inheritance cycles are safe, and a
dangling parent counts as outside the list. A guard that is present but
malformed allows no groups, and a guarded group or track change is
refused as root_only.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Serialise LuckPerms writes between the bridge and Patreon writer
The staff-panel bridge and the Patreon rank writer run on different
threads and both load, change, save and clean up the same users, so
one could reload a user from storage mid-way and drop the other's
change. LuckPermsWriteLock holds one global lock; the Patreon store
holds it around each user write and the bridge around every user,
group and track change. Writes are rare, so one lock is enough.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Keep an outlived bridge pass from running beside a new worker
A pass blocked on storage or the site can outlive stop(), and the old
active flag let it resume under a refreshed worker, racing the new one
on the remembered/unposted results, revision and snapshot state.
Each pass is now bound to the worker generation that scheduled it;
stop() advances the generation. Passes run under one lock, so two
generations never interleave, and per-generation state is reset by the
first pass of a new generation. A superseded pass fetches and publishes
nothing more; a LuckPerms save already in progress completes, and the
rest of its fetched batch is answered save_failed (the site hands out
each change once, so every fetched change still gets a result). stop()
no longer interrupts the worker and waits at most a second, so a
reload never stalls the main thread for long.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Remove a group or track created by a change that then fails
createAndLoadGroup and createAndLoadTrack store the new holder at
once, so a create change whose node, track-group or save step then
failed left an empty group or track behind and answered save_failed;
retrying it returned group_exists or track_exists. The created holder
is now deleted before the failure is returned; an existing holder is
still reloaded from storage.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Treat a player as staff when any inherited group is staff
The admin guard compared only the player's direct groups with the
admin groups. If an allowed group had just gained a staff parent in
LuckPerms before the site's mirror caught up, an admin could still edit
that player. Every positive inheritance node the player holds, in any
context or expiry, now has its live inheritance walked (case-insensitive,
cycle-safe, a missing group counts as outside), and any group outside
the admin groups refuses the change with target_is_staff.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>1 parent c1d7a2e commit 367aa93
20 files changed
Lines changed: 3395 additions & 5 deletions
File tree
- src
- main
- java/net/tfminecraft/tfmcweb
- api
- loaders
- luckperms
- managers
- patreon
- resources
- test/java/net/tfminecraft/tfmcweb
- api
- loaders
- luckperms
- patreon
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
20 | 41 | | |
21 | 42 | | |
22 | 43 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
79 | 86 | | |
80 | 87 | | |
81 | 88 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
| |||
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
| 34 | + | |
33 | 35 | | |
34 | 36 | | |
35 | 37 | | |
| |||
52 | 54 | | |
53 | 55 | | |
54 | 56 | | |
| 57 | + | |
| 58 | + | |
55 | 59 | | |
56 | 60 | | |
57 | 61 | | |
| |||
66 | 70 | | |
67 | 71 | | |
68 | 72 | | |
69 | | - | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
70 | 80 | | |
71 | 81 | | |
72 | 82 | | |
| |||
116 | 126 | | |
117 | 127 | | |
118 | 128 | | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
119 | 132 | | |
120 | 133 | | |
121 | 134 | | |
| |||
134 | 147 | | |
135 | 148 | | |
136 | 149 | | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
137 | 153 | | |
138 | 154 | | |
139 | 155 | | |
| |||
0 commit comments