Hopefully fixed notification regression.

This commit is contained in:
Storm Dragon
2026-05-20 18:36:49 -04:00
parent cc483685ef
commit 1f1f72202e
3 changed files with 238 additions and 18 deletions
+1
View File
@@ -53,6 +53,7 @@ type Barnard struct {
// Added for channel muting
MutedChannels map[uint32]bool
userChannels map[uint32]*gumble.Channel
// Added for noise suppression
NoiseSuppressor *noise.Suppressor
+91 -18
View File
@@ -78,6 +78,7 @@ func (b *Barnard) OnConnect(e *gumble.ConnectEvent) {
// Reset muted channels state on connect
b.MutedChannels = make(map[uint32]bool)
b.userChannels = make(map[uint32]*gumble.Channel)
b.RecordingMutex.Lock()
b.recordingAllowed = nil
b.recordingStarting = false
@@ -89,6 +90,7 @@ func (b *Barnard) OnConnect(e *gumble.ConnectEvent) {
for _, u := range b.Client.Users {
b.UserConfig.UpdateUser(u)
b.rememberUserChannel(u)
}
b.UpdateInputStatus(fmt.Sprintf("[%s]", e.Client.Self.Channel.Name))
@@ -169,6 +171,7 @@ func (b *Barnard) OnTextMessage(e *gumble.TextMessageEvent) {
}
func (b *Barnard) OnUserChange(e *gumble.UserChangeEvent) {
notification, hasNotification := b.userChangeNotification(e)
if e.User != nil {
b.UserConfig.UpdateUser(e.User)
@@ -187,28 +190,14 @@ func (b *Barnard) OnUserChange(e *gumble.UserChangeEvent) {
}
}
var s = "unknown"
var t = "unknown"
if e.Type.Has(gumble.UserChangeConnected) {
s = "joined"
t = "join"
// Notify about users joining our channel
if e.User.Channel.Name == b.Client.Self.Channel.Name {
b.Notify(t, e.User.Name, e.User.Channel.Name)
b.AddOutputLine(fmt.Sprintf("%s %s %s", e.User.Name, s, e.User.Channel.Name))
}
}
if e.Type.Has(gumble.UserChangeDisconnected) {
s = "left"
t = "leave"
if e.User == b.selectedUser {
b.SetSelectedUser(nil)
}
// Always notify about disconnects if user has channel info and was in our channel
if e.User.Channel != nil && e.User.Channel.Name == b.Client.Self.Channel.Name {
b.Notify(t, e.User.Name, e.User.Channel.Name)
b.AddOutputLine(fmt.Sprintf("%s %s %s", e.User.Name, s, e.User.Channel.Name))
}
}
if hasNotification {
b.Notify(notification.event, notification.who, notification.what)
b.AddOutputLine(notification.line)
}
if e.Type.Has(gumble.UserChangeChannel) && e.User == b.Client.Self {
b.UpdateInputStatus(fmt.Sprintf("[%s]", e.User.Channel.Name))
@@ -226,10 +215,94 @@ func (b *Barnard) OnUserChange(e *gumble.UserChangeEvent) {
if e.Type.Has(gumble.UserChangeStats) && e.User.Stats != nil {
b.AddOutputLine(formatUserStats(e.User))
}
b.updateUserChannel(e)
b.UiTree.Rebuild()
b.Ui.Refresh()
}
type userChangeNotification struct {
event string
who string
what string
line string
}
func (b *Barnard) userChangeNotification(e *gumble.UserChangeEvent) (userChangeNotification, bool) {
if e == nil || e.User == nil || b.Client == nil || b.Client.Self == nil || b.Client.Self.Channel == nil {
return userChangeNotification{}, false
}
currentChannel := b.Client.Self.Channel
previousChannel := b.previousUserChannel(e.User)
userChannel := e.User.Channel
if e.Type.Has(gumble.UserChangeConnected) {
return buildUserChangeNotification("join", "joined", e.User, userChannel, currentChannel)
}
if e.Type.Has(gumble.UserChangeDisconnected) {
if previousChannel == nil {
previousChannel = userChannel
}
return buildUserChangeNotification("leave", "left", e.User, previousChannel, currentChannel)
}
if e.Type.Has(gumble.UserChangeChannel) && e.User != b.Client.Self {
if sameChannel(userChannel, currentChannel) && !sameChannel(previousChannel, currentChannel) {
return buildUserChangeNotification("join", "joined", e.User, userChannel, currentChannel)
}
if sameChannel(previousChannel, currentChannel) && !sameChannel(userChannel, currentChannel) {
return buildUserChangeNotification("leave", "left", e.User, previousChannel, currentChannel)
}
}
return userChangeNotification{}, false
}
func buildUserChangeNotification(event string, verb string, user *gumble.User, eventChannel *gumble.Channel, currentChannel *gumble.Channel) (userChangeNotification, bool) {
if !sameChannel(eventChannel, currentChannel) {
return userChangeNotification{}, false
}
return userChangeNotification{
event: event,
who: user.Name,
what: eventChannel.Name,
line: fmt.Sprintf("%s %s %s", user.Name, verb, eventChannel.Name),
}, true
}
func sameChannel(a *gumble.Channel, b *gumble.Channel) bool {
return a != nil && b != nil && a.ID == b.ID
}
func (b *Barnard) previousUserChannel(user *gumble.User) *gumble.Channel {
if b.userChannels == nil || user == nil {
return nil
}
return b.userChannels[user.Session]
}
func (b *Barnard) rememberUserChannel(user *gumble.User) {
if user == nil || user.Channel == nil {
return
}
if b.userChannels == nil {
b.userChannels = make(map[uint32]*gumble.Channel)
}
b.userChannels[user.Session] = user.Channel
}
func (b *Barnard) updateUserChannel(e *gumble.UserChangeEvent) {
if e == nil || e.User == nil {
return
}
if e.Type.Has(gumble.UserChangeDisconnected) {
if b.userChannels != nil {
delete(b.userChannels, e.User.Session)
}
return
}
b.rememberUserChannel(e.User)
}
func (b *Barnard) OnChannelChange(e *gumble.ChannelChangeEvent) {
b.UpdateInputStatus(fmt.Sprintf("[%s]", e.Channel.Name))
if e.Type.Has(gumble.ChannelChangeDescription) {
+146
View File
@@ -0,0 +1,146 @@
package main
import (
"testing"
"git.stormux.org/storm/barnard/gumble/gumble"
)
func TestUserChangeNotification(t *testing.T) {
current := &gumble.Channel{ID: 1, Name: "Current"}
other := &gumble.Channel{ID: 2, Name: "Other"}
self := &gumble.User{Session: 1, Name: "Username", Channel: current}
tests := []struct {
name string
user *gumble.User
previous *gumble.Channel
change gumble.UserChangeType
want userChangeNotification
wantOK bool
}{
{
name: "connected to current channel",
user: &gumble.User{Session: 2, Name: "Guest", Channel: current},
change: gumble.UserChangeConnected,
want: userChangeNotification{
event: "join",
who: "Guest",
what: "Current",
line: "Guest joined Current",
},
wantOK: true,
},
{
name: "disconnected from current channel",
user: &gumble.User{Session: 2, Name: "Guest", Channel: current},
previous: current,
change: gumble.UserChangeDisconnected,
want: userChangeNotification{
event: "leave",
who: "Guest",
what: "Current",
line: "Guest left Current",
},
wantOK: true,
},
{
name: "moved into current channel",
user: &gumble.User{Session: 2, Name: "Guest", Channel: current},
previous: other,
change: gumble.UserChangeChannel,
want: userChangeNotification{
event: "join",
who: "Guest",
what: "Current",
line: "Guest joined Current",
},
wantOK: true,
},
{
name: "moved out of current channel",
user: &gumble.User{Session: 2, Name: "Guest", Channel: other},
previous: current,
change: gumble.UserChangeChannel,
want: userChangeNotification{
event: "leave",
who: "Guest",
what: "Current",
line: "Guest left Current",
},
wantOK: true,
},
{
name: "connected to other channel",
user: &gumble.User{Session: 2, Name: "Guest", Channel: other},
change: gumble.UserChangeConnected,
},
{
name: "moved between other channels",
user: &gumble.User{Session: 2, Name: "Guest", Channel: other},
previous: &gumble.Channel{ID: 3, Name: "Elsewhere"},
change: gumble.UserChangeChannel,
},
{
name: "self channel move",
user: self,
previous: other,
change: gumble.UserChangeChannel,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := &Barnard{
Client: &gumble.Client{Self: self},
}
if tt.previous != nil {
b.userChannels = map[uint32]*gumble.Channel{tt.user.Session: tt.previous}
}
got, ok := b.userChangeNotification(&gumble.UserChangeEvent{
Client: b.Client,
Type: tt.change,
User: tt.user,
})
if ok != tt.wantOK {
t.Fatalf("expected ok %v, got %v", tt.wantOK, ok)
}
if got != tt.want {
t.Fatalf("expected %#v, got %#v", tt.want, got)
}
})
}
}
func TestUpdateUserChannel(t *testing.T) {
current := &gumble.Channel{ID: 1, Name: "Current"}
other := &gumble.Channel{ID: 2, Name: "Other"}
user := &gumble.User{Session: 2, Name: "Guest", Channel: current}
b := &Barnard{}
b.updateUserChannel(&gumble.UserChangeEvent{
Type: gumble.UserChangeConnected,
User: user,
})
if got := b.previousUserChannel(user); got != current {
t.Fatalf("expected current channel to be remembered, got %#v", got)
}
user.Channel = other
b.updateUserChannel(&gumble.UserChangeEvent{
Type: gumble.UserChangeChannel,
User: user,
})
if got := b.previousUserChannel(user); got != other {
t.Fatalf("expected other channel to be remembered, got %#v", got)
}
b.updateUserChannel(&gumble.UserChangeEvent{
Type: gumble.UserChangeDisconnected,
User: user,
})
if got := b.previousUserChannel(user); got != nil {
t.Fatalf("expected disconnected user channel to be removed, got %#v", got)
}
}