From 3efbd019ce516e78b28602f0a6661eb775108680 Mon Sep 17 00:00:00 2001 From: "Brandon McGinty (chatgpt)" Date: Mon, 10 Aug 2026 00:42:09 -0400 Subject: [PATCH] Synchronize selected user access --- admin.go | 2 +- barnard.go | 43 ++++++++++++++++++++++++------------- client.go | 2 +- client_notification_test.go | 15 +++++++++++++ ui.go | 8 +++---- 5 files changed, 49 insertions(+), 21 deletions(-) diff --git a/admin.go b/admin.go index 9889f43..757f4db 100644 --- a/admin.go +++ b/admin.go @@ -65,7 +65,7 @@ func (b *Barnard) OpenAdminMenu() { return } b.adminReturnItem = b.UiTree.ActiveItem() - b.adminTargetUser = b.selectedUser + b.adminTargetUser = b.selectedUserValue() b.adminTargetChan = b.Client.Self.Channel if b.Ui.Active() == uiViewTree { switch item := b.UiTree.ActiveItem().(type) { diff --git a/barnard.go b/barnard.go index da94e2c..c4305c7 100644 --- a/barnard.go +++ b/barnard.go @@ -32,20 +32,21 @@ type Barnard struct { AutoTransmit bool // auto-start transmission on connect Connected bool - Ui *uiterm.Ui - UiOutput uiterm.Textview - UiInput uiterm.Textbox - UiStatus uiterm.Label - UiTree uiterm.Tree - UiAdmin uiterm.Tree - UiInputStatus uiterm.Label - SelectedChannel *gumble.Channel - selectedUser *gumble.User - adminTargetUser *gumble.User - adminTargetChan *gumble.Channel - adminReturnItem uiterm.TreeItem - statusText string - statusNotice bool + Ui *uiterm.Ui + UiOutput uiterm.Textview + UiInput uiterm.Textbox + UiStatus uiterm.Label + UiTree uiterm.Tree + UiAdmin uiterm.Tree + UiInputStatus uiterm.Label + SelectedChannel *gumble.Channel + selectedUser *gumble.User + selectedUserMutex sync.RWMutex + adminTargetUser *gumble.User + adminTargetChan *gumble.Channel + adminReturnItem uiterm.TreeItem + statusText string + statusNotice bool notifyChannel chan []string @@ -136,6 +137,18 @@ func (b *Barnard) setChannelMuted(channelID uint32, muted bool) { } } +func (b *Barnard) selectedUserValue() *gumble.User { + b.selectedUserMutex.RLock() + defer b.selectedUserMutex.RUnlock() + return b.selectedUser +} + +func (b *Barnard) setSelectedUserValue(user *gumble.User) { + b.selectedUserMutex.Lock() + b.selectedUser = user + b.selectedUserMutex.Unlock() +} + func (b *Barnard) StopTransmission() { if b.Tx { b.Notify("micdown", "me", "") @@ -165,7 +178,7 @@ func (b *Barnard) TreeItemKeyPress(ui *uiterm.Ui, tree *uiterm.Tree, item uiterm b.GotoChat() } if treeItem.User != nil { - if b.selectedUser == treeItem.User { + if b.selectedUserValue() == treeItem.User { b.SetSelectedUser(nil) b.GotoChat() } else { diff --git a/client.go b/client.go index 2483577..3e78575 100644 --- a/client.go +++ b/client.go @@ -294,7 +294,7 @@ func (b *Barnard) OnUserChange(e *gumble.UserChangeEvent) { } if e.Type.Has(gumble.UserChangeDisconnected) { - if e.User == b.selectedUser { + if e.User == b.selectedUserValue() { b.SetSelectedUser(nil) } } diff --git a/client_notification_test.go b/client_notification_test.go index cf2fd67..392236d 100644 --- a/client_notification_test.go +++ b/client_notification_test.go @@ -84,6 +84,21 @@ func TestServerAddressDefaultsPortWithoutBreakingIPv6(t *testing.T) { } } +func TestConcurrentSelectedUserAccess(t *testing.T) { + b := &Barnard{} + user := &gumble.User{Session: 1} + var wg sync.WaitGroup + for i := 0; i < 20; i++ { + wg.Add(1) + go func(user *gumble.User) { + defer wg.Done() + b.setSelectedUserValue(user) + _ = b.selectedUserValue() + }(user) + } + wg.Wait() +} + func TestConcurrentMutedChannelAccess(t *testing.T) { b := &Barnard{MutedChannels: make(map[uint32]bool)} var wg sync.WaitGroup diff --git a/ui.go b/ui.go index 2daf5ef..fab2ab2 100644 --- a/ui.go +++ b/ui.go @@ -57,7 +57,7 @@ func (b *Barnard) Notify(event string, who string, what string) { } func (b *Barnard) SetSelectedUser(user *gumble.User) { - b.selectedUser = user + b.setSelectedUserValue(user) if user == nil { if len(b.UiInput.Text) > 0 { } @@ -493,9 +493,9 @@ func (b *Barnard) OnTextInput(ui *uiterm.Ui, textbox *uiterm.Textbox, text strin // Not a command, send as chat message if b.Client != nil && b.Client.Self != nil { - if b.selectedUser != nil { - b.selectedUser.Send(text) - b.AddOutputPrivateMessage(b.Client.Self, b.selectedUser, text) + if selectedUser := b.selectedUserValue(); selectedUser != nil { + selectedUser.Send(text) + b.AddOutputPrivateMessage(b.Client.Self, selectedUser, text) } else { b.Client.Self.Channel.Send(text, false) b.AddOutputMessage(b.Client.Self, text)