mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-21 03:12:41 +00:00
adventure: fix concurrency + dup hazards in web equip path
Code review of the Ask-7 web equipment-management path surfaced three correctness issues, all fixed here: - applyEquipOrder ran the poll-goroutine equip mutations without the per-user advUserLock that every Matrix-side mutation (!give, !equip, arena, …) holds, so the lock gave no mutual exclusion against the web path. A concurrent !give of the item being equipped could duplicate it. Now takes advUserLock(owner) for the whole apply, matching the DM path. - applyMasterworkEquip evicted the displaced occupant to the pack BEFORE the destructive slot write, so a fault left the piece both worn and in the pack — and the 30s equip poll retry re-evicted it every tick. Now removes the incoming row, writes the slot, then re-packs the occupant last as a best-effort step: once the slot no longer references it, the re-pack cannot duplicate, and a failure is logged not aborted on (the DM confirm handler's tolerance). - PlayerDetail.Balance dropped omitempty: a real €0 balance is an informative fact, not an absent one, and omitting it left the web confirm dialog with no balance to show.
This commit is contained in:
@@ -122,6 +122,14 @@ func (p *AdventurePlugin) fulfilEquipOrder(ctx context.Context, order peteclient
|
||||
// a human note for Pete, or retry=true for a transient fault that should leave the
|
||||
// order pending. It records nothing and pushes nothing — the caller does both.
|
||||
func (p *AdventurePlugin) applyEquipOrder(owner id.UserID, order peteclient.EquipOrder) (status, detail string, retry bool) {
|
||||
// Serialize against the owner's own Matrix-side mutations (!give, !equip, !sell,
|
||||
// arena, …), all of which hold this same per-user lock. Without it the poll
|
||||
// goroutine's equip could interleave with a concurrent !give of the very item it
|
||||
// resolved — the duplication the DM equip confirm takes this lock to prevent.
|
||||
userMu := p.advUserLock(owner)
|
||||
userMu.Lock()
|
||||
defer userMu.Unlock()
|
||||
|
||||
switch order.Action {
|
||||
case "equip":
|
||||
inv, err := loadAdvInventory(owner)
|
||||
|
||||
Reference in New Issue
Block a user