From 2f4bf65d20b5c233a62a50da26f7793298110a4b Mon Sep 17 00:00:00 2001 From: Steve Date: Wed, 6 Jan 2021 19:12:56 -0500 Subject: [PATCH] add mutexs to prevent data races, re-organize a bit --- bridge.go | 16 ++++++++++------ config.go | 1 - handlers.go | 50 ++++++++++++++++++++++++++++++++++++++++++++------ main.go | 18 +++++++++++++----- 4 files changed, 67 insertions(+), 18 deletions(-) diff --git a/bridge.go b/bridge.go index 2962f2e..3b1b4d0 100644 --- a/bridge.go +++ b/bridge.go @@ -12,12 +12,12 @@ import ( "github.com/bwmarrin/discordgo" "layeh.com/gumble/gumble" - "layeh.com/gumble/gumbleutil" ) type BridgeState struct { ActiveConn chan bool Connected bool + Mode BridgeMode Client *gumble.Client DiscordUsers map[string]bool MumbleUsers map[string]bool @@ -46,10 +46,7 @@ func startBridge(discord *discordgo.Session, discordGID string, discordCID strin if l.BridgeConf.MumbleInsecure { tlsConfig.InsecureSkipVerify = true } - l.BridgeConf.Config.Attach(gumbleutil.Listener{ - Connect: l.mumbleConnect, - UserChange: l.mumbleUserChange, - }) + mumble, err := gumble.DialWithDialer(new(net.Dialer), l.BridgeConf.MumbleAddr, l.BridgeConf.Config, &tlsConfig) if err != nil { @@ -100,8 +97,9 @@ func startBridge(discord *discordgo.Session, discordGID string, discordCID strin } } }() - + l.ConnectedLock.Lock() l.Bridge.Connected = true + l.ConnectedLock.Unlock() select { case sig := <-c: @@ -134,6 +132,8 @@ func discordStatusUpdate(dg *discordgo.Session, host, port string, l *Listener) log.Printf("error pinging mumble server %v\n", err) dg.UpdateListeningStatus("an error pinging mumble") } else { + l.UserCountLock.Lock() + l.ConnectedLock.Lock() curr = resp.ConnectedUsers if l.Bridge.Connected { curr = curr - 1 @@ -150,6 +150,8 @@ func discordStatusUpdate(dg *discordgo.Session, host, port string, l *Listener) status = fmt.Sprintf("%v users in Mumble\n", curr) } } + l.ConnectedLock.Unlock() + l.UserCountLock.Unlock() dg.UpdateListeningStatus(status) } } @@ -165,6 +167,7 @@ func AutoBridge(s *discordgo.Session, l *Listener) { return } time.Sleep(3 * time.Second) + l.UserCountLock.Lock() if !l.Bridge.Connected && l.Bridge.MumbleUserCount > 0 && l.Bridge.DiscordUserCount > 0 { log.Println("users detected in mumble and discord, bridging") die := make(chan bool) @@ -177,5 +180,6 @@ func AutoBridge(s *discordgo.Session, l *Listener) { MumbleReset() DiscordReset() } + l.UserCountLock.Unlock() } } diff --git a/config.go b/config.go index 5fd9885..cf58b82 100644 --- a/config.go +++ b/config.go @@ -23,7 +23,6 @@ type BridgeConfig struct { MumbleAddr string MumbleInsecure bool MumbleChannel string - Mode BridgeMode Command string GID string CID string diff --git a/handlers.go b/handlers.go index 9a1a287..a22101f 100644 --- a/handlers.go +++ b/handlers.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "strings" + "sync" "time" "github.com/bwmarrin/discordgo" @@ -11,17 +12,43 @@ import ( ) type Listener struct { - BridgeConf *BridgeConfig - Bridge *BridgeState + BridgeConf *BridgeConfig + Bridge *BridgeState + UserCountLock *sync.Mutex + ConnectedLock *sync.Mutex } func (l *Listener) ready(s *discordgo.Session, event *discordgo.Ready) { log.Println("READY event registered") + //Setup initial discord state + var g *discordgo.Guild + for _, i := range event.Guilds { + if i.ID == l.BridgeConf.GID { + g = i + } + } + for _, vs := range g.VoiceStates { + if vs.ChannelID == l.BridgeConf.CID { + l.UserCountLock.Lock() + l.Bridge.DiscordUserCount = l.Bridge.DiscordUserCount + 1 + u, err := s.User(vs.UserID) + if err != nil { + log.Println("error looking up username") + } + l.Bridge.DiscordUsers[u.Username] = true + if l.Bridge.Connected { + l.Bridge.Client.Do(func() { + l.Bridge.Client.Self.Channel.Send(fmt.Sprintf("%v has joined Discord channel\n", u.Username), false) + }) + } + l.UserCountLock.Unlock() + } + } } func (l *Listener) messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { - if l.BridgeConf.Mode == BridgeModeConstant { + if l.Bridge.Mode == BridgeModeConstant { return } @@ -119,13 +146,13 @@ func (l *Listener) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat } if strings.HasPrefix(m.Content, prefix+" auto") { - if l.BridgeConf.Mode != BridgeModeAuto { - l.BridgeConf.Mode = BridgeModeAuto + if l.Bridge.Mode != BridgeModeAuto { + l.Bridge.Mode = BridgeModeAuto l.Bridge.AutoChan = make(chan bool) go AutoBridge(s, l) } else { l.Bridge.AutoChan <- true - l.BridgeConf.Mode = BridgeModeManual + l.Bridge.Mode = BridgeModeManual } } } @@ -145,6 +172,7 @@ func (l *Listener) guildCreate(s *discordgo.Session, event *discordgo.GuildCreat } func (l *Listener) voiceUpdate(s *discordgo.Session, event *discordgo.VoiceStateUpdate) { + l.UserCountLock.Lock() if event.GuildID == l.BridgeConf.GID { if event.ChannelID == l.BridgeConf.CID { //get user @@ -155,16 +183,20 @@ func (l *Listener) voiceUpdate(s *discordgo.Session, event *discordgo.VoiceState //check to see if actually new user if l.Bridge.DiscordUsers[u.Username] { //not actually new user + l.UserCountLock.Unlock() return } log.Println("user joined watched discord channel") + l.ConnectedLock.Lock() if l.Bridge.Connected { l.Bridge.Client.Do(func() { l.Bridge.Client.Self.Channel.Send(fmt.Sprintf("%v has joined Discord channel\n", u.Username), false) }) } + l.ConnectedLock.Unlock() l.Bridge.DiscordUsers[u.Username] = true l.Bridge.DiscordUserCount = l.Bridge.DiscordUserCount + 1 + l.UserCountLock.Unlock() } if event.ChannelID == "" { //leave event, trigger recount of active users @@ -172,6 +204,7 @@ func (l *Listener) voiceUpdate(s *discordgo.Session, event *discordgo.VoiceState g, err := s.State.Guild(event.GuildID) if err != nil { // Could not find guild. + l.UserCountLock.Unlock() return } @@ -189,12 +222,15 @@ func (l *Listener) voiceUpdate(s *discordgo.Session, event *discordgo.VoiceState } delete(l.Bridge.DiscordUsers, u.Username) log.Println("user left watched discord channel") + l.ConnectedLock.Lock() if l.Bridge.Connected { l.Bridge.Client.Do(func() { l.Bridge.Client.Self.Channel.Send(fmt.Sprintf("%v has left Discord channel\n", u.Username), false) }) } + l.ConnectedLock.Unlock() l.Bridge.DiscordUserCount = count + l.UserCountLock.Unlock() } } @@ -213,6 +249,7 @@ func (l *Listener) mumbleConnect(e *gumble.ConnectEvent) { } func (l *Listener) mumbleUserChange(e *gumble.UserChangeEvent) { + l.UserCountLock.Lock() if e.Type.Has(gumble.UserChangeConnected) || e.Type.Has(gumble.UserChangeChannel) || e.Type.Has(gumble.UserChangeDisconnected) { l.Bridge.MumbleUsers = make(map[string]bool) for _, user := range l.Bridge.Client.Self.Channel.Users { @@ -224,4 +261,5 @@ func (l *Listener) mumbleUserChange(e *gumble.UserChangeEvent) { } } } + l.UserCountLock.Unlock() } diff --git a/main.go b/main.go index 9416024..77ce55b 100644 --- a/main.go +++ b/main.go @@ -6,12 +6,14 @@ import ( "os" "os/signal" "strconv" + "sync" "syscall" "time" "github.com/bwmarrin/discordgo" "github.com/joho/godotenv" "layeh.com/gumble/gumble" + "layeh.com/gumble/gumbleutil" _ "layeh.com/gumble/opus" ) @@ -75,7 +77,6 @@ func main() { MumbleAddr: *mumbleAddr + ":" + strconv.Itoa(*mumblePort), MumbleInsecure: *mumbleInsecure, MumbleChannel: *mumbleChannel, - Mode: -1, Command: *discordCommand, GID: *discordGID, CID: *discordCID, @@ -86,8 +87,11 @@ func main() { MumbleUserCount: 0, DiscordUserCount: 0, DiscordUsers: make(map[string]bool), + MumbleUsers: make(map[string]bool), } - l := &Listener{BridgeConf, Bridge} + ul := &sync.Mutex{} + cl := &sync.Mutex{} + l := &Listener{BridgeConf, Bridge, ul, cl} // Discord setup // Open Websocket @@ -100,6 +104,10 @@ func main() { discord.AddHandler(l.guildCreate) discord.AddHandler(l.voiceUpdate) err = discord.Open() + l.BridgeConf.Config.Attach(gumbleutil.Listener{ + Connect: l.mumbleConnect, + UserChange: l.mumbleUserChange, + }) if err != nil { log.Println(err) return @@ -113,14 +121,14 @@ func main() { case "auto": log.Println("bridge starting in automatic mode") Bridge.AutoChan = make(chan bool) - BridgeConf.Mode = BridgeModeAuto + Bridge.Mode = BridgeModeAuto go AutoBridge(discord, l) case "manual": log.Println("bridge starting in manual mode") - BridgeConf.Mode = BridgeModeManual + Bridge.Mode = BridgeModeManual case "constant": log.Println("bridge starting in constant mode") - BridgeConf.Mode = BridgeModeConstant + Bridge.Mode = BridgeModeConstant go startBridge(discord, *discordGID, *discordCID, l, make(chan bool)) default: discord.Close()