From bcd7ee97ba6ff6fbf60d9754d29ca00d039b4af8 Mon Sep 17 00:00:00 2001 From: Steve Date: Tue, 5 Jan 2021 19:43:55 -0500 Subject: [PATCH 1/4] mumble event listeners use non-global state --- bridge.go | 18 +++++++++--------- handlers.go | 23 ++++++++++++++--------- main.go | 5 +++-- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/bridge.go b/bridge.go index 48a84b8..b8a7caf 100644 --- a/bridge.go +++ b/bridge.go @@ -26,7 +26,7 @@ type BridgeState struct { AutoChan chan bool } -func startBridge(discord *discordgo.Session, discordGID string, discordCID string, config *gumble.Config, mumbleAddr string, mumbleInsecure bool, die chan bool) { +func startBridge(discord *discordgo.Session, discordGID string, discordCID string, l *Listener, die chan bool) { dgv, err := discord.ChannelVoiceJoin(discordGID, discordCID, false, false) if err != nil { log.Println(err) @@ -43,14 +43,14 @@ func startBridge(discord *discordgo.Session, discordGID string, discordCID strin } var tlsConfig tls.Config - if mumbleInsecure { + if l.BridgeConf.MumbleInsecure { tlsConfig.InsecureSkipVerify = true } - config.Attach(gumbleutil.Listener{ - Connect: mumbleConnect, - UserChange: mumbleUserChange, + l.BridgeConf.Config.Attach(gumbleutil.Listener{ + Connect: l.mumbleConnect, + UserChange: l.mumbleUserChange, }) - mumble, err := gumble.DialWithDialer(new(net.Dialer), mumbleAddr, config, &tlsConfig) + mumble, err := gumble.DialWithDialer(new(net.Dialer), l.BridgeConf.MumbleAddr, l.BridgeConf.Config, &tlsConfig) if err != nil { log.Println(err) @@ -68,7 +68,7 @@ func startBridge(discord *discordgo.Session, discordGID string, discordCID strin // Start Passing Between // Mumble go m.fromMumbleMixer(toDiscord, die) - det := config.AudioListeners.Attach(m) + det := l.BridgeConf.Config.AudioListeners.Attach(m) //Discord go discordReceivePCM(dgv, die) @@ -173,7 +173,7 @@ func discordStatusUpdate(dg *discordgo.Session, host, port string) { } } -func AutoBridge(s *discordgo.Session) { +func AutoBridge(s *discordgo.Session, l *Listener) { log.Println("beginning auto mode") for { select { @@ -187,7 +187,7 @@ func AutoBridge(s *discordgo.Session) { log.Println("users detected in mumble and discord, bridging") die := make(chan bool) Bridge.ActiveConn = die - go startBridge(s, BridgeConf.GID, BridgeConf.CID, BridgeConf.Config, BridgeConf.MumbleAddr, BridgeConf.MumbleInsecure, die) + go startBridge(s, BridgeConf.GID, BridgeConf.CID, l, die) } if Bridge.Connected && Bridge.MumbleUserCount == 0 && Bridge.DiscordUserCount <= 1 { log.Println("no one online, killing bridge") diff --git a/handlers.go b/handlers.go index 256108f..b0a4c25 100644 --- a/handlers.go +++ b/handlers.go @@ -10,6 +10,11 @@ import ( "layeh.com/gumble/gumble" ) +type Listener struct { + BridgeConf *BridgeConfig + Bridge *BridgeState +} + func ready(s *discordgo.Session, event *discordgo.Ready) { log.Println("READY event registered") } @@ -47,7 +52,7 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { log.Printf("Trying to join GID %v and VID %v\n", g.ID, vs.ChannelID) die := make(chan bool) Bridge.ActiveConn = die - go startBridge(s, g.ID, vs.ChannelID, BridgeConf.Config, BridgeConf.MumbleAddr, BridgeConf.MumbleInsecure, die) + //go startBridge(s, g.ID, vs.ChannelID, BridgeConf.Config, BridgeConf.MumbleAddr, BridgeConf.MumbleInsecure, die) return } } @@ -107,7 +112,7 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { DiscordReset() time.Sleep(5 * time.Second) Bridge.ActiveConn = make(chan bool) - go startBridge(s, g.ID, vs.ChannelID, BridgeConf.Config, BridgeConf.MumbleAddr, BridgeConf.MumbleInsecure, Bridge.ActiveConn) + //go startBridge(s, g.ID, vs.ChannelID, BridgeConf.Config, BridgeConf.MumbleAddr, BridgeConf.MumbleInsecure, Bridge.ActiveConn) return } } @@ -117,7 +122,7 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { if BridgeConf.Mode != BridgeModeAuto { BridgeConf.Mode = BridgeModeAuto Bridge.AutoChan = make(chan bool) - go AutoBridge(s) + //go AutoBridge(s) } else { Bridge.AutoChan <- true BridgeConf.Mode = BridgeModeManual @@ -198,8 +203,8 @@ func voiceUpdate(s *discordgo.Session, event *discordgo.VoiceStateUpdate) { return } -func mumbleConnect(e *gumble.ConnectEvent) { - if BridgeConf.MumbleChannel != "" { +func (l *Listener) mumbleConnect(e *gumble.ConnectEvent) { + if l.BridgeConf.MumbleChannel != "" { //join specified channel startingChannel := e.Client.Channels.Find(BridgeConf.MumbleChannel) if startingChannel != nil { @@ -208,15 +213,15 @@ func mumbleConnect(e *gumble.ConnectEvent) { } } -func mumbleUserChange(e *gumble.UserChangeEvent) { +func (l *Listener) mumbleUserChange(e *gumble.UserChangeEvent) { if e.Type.Has(gumble.UserChangeConnected) || e.Type.Has(gumble.UserChangeChannel) || e.Type.Has(gumble.UserChangeDisconnected) { Bridge.MumbleUsers = make(map[string]bool) - for _, user := range Bridge.Client.Self.Channel.Users { + for _, user := range l.Bridge.Client.Self.Channel.Users { //note, this might be too slow for really really big channels? //event listeners block while processing //also probably bad to rebuild the set every user change. - if user.Name != Bridge.Client.Self.Name { - Bridge.MumbleUsers[user.Name] = true + if user.Name != l.Bridge.Client.Self.Name { + l.Bridge.MumbleUsers[user.Name] = true } } } diff --git a/main.go b/main.go index 10dad71..b4d0fff 100644 --- a/main.go +++ b/main.go @@ -109,19 +109,20 @@ func main() { DiscordUserCount: 0, DiscordUsers: make(map[string]bool), } + l := &Listener{BridgeConf, Bridge} switch *mode { case "auto": log.Println("bridge starting in automatic mode") Bridge.AutoChan = make(chan bool) BridgeConf.Mode = BridgeModeAuto - go AutoBridge(discord) + //go AutoBridge(discord,l) case "manual": log.Println("bridge starting in manual mode") BridgeConf.Mode = BridgeModeManual case "constant": log.Println("bridge starting in constant mode") BridgeConf.Mode = BridgeModeConstant - go startBridge(discord, *discordGID, *discordCID, config, BridgeConf.MumbleAddr, *mumbleInsecure, make(chan bool)) + go startBridge(discord, *discordGID, *discordCID, l, make(chan bool)) default: discord.Close() log.Fatalln("invalid bridge mode set") From ac800167f6872c0e24895a3c65eac5451dfe075b Mon Sep 17 00:00:00 2001 From: Steve Date: Tue, 5 Jan 2021 20:21:08 -0500 Subject: [PATCH 2/4] discord event listeners use non-global state --- handlers.go | 38 +++++++++++++++++++------------------- main.go | 44 +++++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/handlers.go b/handlers.go index b0a4c25..2d0b4b1 100644 --- a/handlers.go +++ b/handlers.go @@ -15,13 +15,13 @@ type Listener struct { Bridge *BridgeState } -func ready(s *discordgo.Session, event *discordgo.Ready) { +func (l *Listener) ready(s *discordgo.Session, event *discordgo.Ready) { log.Println("READY event registered") } -func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { +func (l *Listener) messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { - if BridgeConf.Mode == BridgeModeConstant { + if l.BridgeConf.Mode == BridgeModeConstant { return } @@ -29,7 +29,7 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { if m.Author.ID == s.State.User.ID { return } - prefix := "!" + BridgeConf.Command + prefix := "!" + l.BridgeConf.Command if strings.HasPrefix(m.Content, prefix+" link") { // Find the channel that the message came from. @@ -51,8 +51,8 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { if vs.UserID == m.Author.ID { log.Printf("Trying to join GID %v and VID %v\n", g.ID, vs.ChannelID) die := make(chan bool) - Bridge.ActiveConn = die - //go startBridge(s, g.ID, vs.ChannelID, BridgeConf.Config, BridgeConf.MumbleAddr, BridgeConf.MumbleInsecure, die) + l.Bridge.ActiveConn = die + go startBridge(s, g.ID, vs.ChannelID, l, die) return } } @@ -78,8 +78,8 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { for _, vs := range g.VoiceStates { if vs.UserID == m.Author.ID { log.Printf("Trying to leave GID %v and VID %v\n", g.ID, vs.ChannelID) - Bridge.ActiveConn <- true - Bridge.ActiveConn = nil + l.Bridge.ActiveConn <- true + l.Bridge.ActiveConn = nil MumbleReset() DiscordReset() return @@ -107,30 +107,30 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { for _, vs := range g.VoiceStates { if vs.UserID == m.Author.ID { log.Printf("Trying to refresh GID %v and VID %v\n", g.ID, vs.ChannelID) - Bridge.ActiveConn <- true + l.Bridge.ActiveConn <- true MumbleReset() DiscordReset() time.Sleep(5 * time.Second) - Bridge.ActiveConn = make(chan bool) - //go startBridge(s, g.ID, vs.ChannelID, BridgeConf.Config, BridgeConf.MumbleAddr, BridgeConf.MumbleInsecure, Bridge.ActiveConn) + l.Bridge.ActiveConn = make(chan bool) + go startBridge(s, g.ID, vs.ChannelID, l, l.Bridge.ActiveConn) return } } } if strings.HasPrefix(m.Content, prefix+" auto") { - if BridgeConf.Mode != BridgeModeAuto { - BridgeConf.Mode = BridgeModeAuto - Bridge.AutoChan = make(chan bool) - //go AutoBridge(s) + if l.BridgeConf.Mode != BridgeModeAuto { + l.BridgeConf.Mode = BridgeModeAuto + l.Bridge.AutoChan = make(chan bool) + go AutoBridge(s, l) } else { - Bridge.AutoChan <- true - BridgeConf.Mode = BridgeModeManual + l.Bridge.AutoChan <- true + l.BridgeConf.Mode = BridgeModeManual } } } -func guildCreate(s *discordgo.Session, event *discordgo.GuildCreate) { +func (l *Listener) guildCreate(s *discordgo.Session, event *discordgo.GuildCreate) { if event.Guild.Unavailable { return @@ -144,7 +144,7 @@ func guildCreate(s *discordgo.Session, event *discordgo.GuildCreate) { } } -func voiceUpdate(s *discordgo.Session, event *discordgo.VoiceStateUpdate) { +func (l *Listener) voiceUpdate(s *discordgo.Session, event *discordgo.VoiceStateUpdate) { if event.GuildID == BridgeConf.GID { if event.ChannelID == BridgeConf.CID { //get user diff --git a/main.go b/main.go index b4d0fff..597de55 100644 --- a/main.go +++ b/main.go @@ -59,32 +59,13 @@ func main() { log.Println("Unable to set priority. ", err) } - // DISCORD Setup - + //Connect to discord discord, err := discordgo.New("Bot " + *discordToken) if err != nil { log.Println(err) return } - // Open Websocket - discord.LogLevel = 2 - discord.StateEnabled = true - discord.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAllWithoutPrivileged) - // register handlers - discord.AddHandler(ready) - discord.AddHandler(messageCreate) - discord.AddHandler(guildCreate) - discord.AddHandler(voiceUpdate) - err = discord.Open() - if err != nil { - log.Println(err) - return - } - defer discord.Close() - - log.Println("Discord Bot Connected") - log.Printf("Discord bot looking for command !%v", *discordCommand) // Mumble setup config := gumble.NewConfig() config.Username = *mumbleUsername @@ -110,12 +91,33 @@ func main() { DiscordUsers: make(map[string]bool), } l := &Listener{BridgeConf, Bridge} + + // Discord setup + // Open Websocket + discord.LogLevel = 2 + discord.StateEnabled = true + discord.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAllWithoutPrivileged) + // register handlers + discord.AddHandler(l.ready) + discord.AddHandler(l.messageCreate) + discord.AddHandler(l.guildCreate) + discord.AddHandler(l.voiceUpdate) + err = discord.Open() + if err != nil { + log.Println(err) + return + } + defer discord.Close() + + log.Println("Discord Bot Connected") + log.Printf("Discord bot looking for command !%v", *discordCommand) + switch *mode { case "auto": log.Println("bridge starting in automatic mode") Bridge.AutoChan = make(chan bool) BridgeConf.Mode = BridgeModeAuto - //go AutoBridge(discord,l) + go AutoBridge(discord, l) case "manual": log.Println("bridge starting in manual mode") BridgeConf.Mode = BridgeModeManual From db0af7edcd0b2a31eb2c880e8081d66d5d9b9221 Mon Sep 17 00:00:00 2001 From: Steve Date: Tue, 5 Jan 2021 20:25:38 -0500 Subject: [PATCH 3/4] remove global conf and state variables --- bridge.go | 47 ++++++++++++++++++++++++----------------------- handlers.go | 36 ++++++++++++++++++------------------ main.go | 9 +++------ 3 files changed, 45 insertions(+), 47 deletions(-) diff --git a/bridge.go b/bridge.go index b8a7caf..5c2522d 100644 --- a/bridge.go +++ b/bridge.go @@ -57,7 +57,7 @@ func startBridge(discord *discordgo.Session, discordGID string, discordCID strin return } defer mumble.Disconnect() - Bridge.Client = mumble + l.Bridge.Client = mumble // Shared Channels // Shared channels pass PCM information in 10ms chunks [480]int16 var toMumble = mumble.AudioOutgoing() @@ -109,18 +109,18 @@ func startBridge(discord *discordgo.Session, discordGID string, discordCID strin } for _, vs := range g.VoiceStates { if vs.ChannelID == discordCID { - Bridge.DiscordUserCount = Bridge.DiscordUserCount + 1 + l.Bridge.DiscordUserCount = l.Bridge.DiscordUserCount + 1 u, err := discord.User(vs.UserID) if err != nil { log.Println("error looking up username") - Bridge.DiscordUsers[u.Username] = true - Bridge.Client.Do(func() { - Bridge.Client.Self.Channel.Send(fmt.Sprintf("%v has joined Discord channel\n", u.Username), false) + l.Bridge.DiscordUsers[u.Username] = true + l.Bridge.Client.Do(func() { + l.Bridge.Client.Self.Channel.Send(fmt.Sprintf("%v has joined Discord channel\n", u.Username), false) }) } } } - Bridge.Connected = true + l.Bridge.Connected = true select { case sig := <-c: @@ -132,15 +132,16 @@ func startBridge(discord *discordgo.Session, discordGID string, discordCID strin close(die) close(m.Close) close(toMumble) - Bridge.Connected = false - Bridge.Client = nil - Bridge.MumbleUserCount = 0 - Bridge.DiscordUserCount = 0 - Bridge.DiscordUsers = make(map[string]bool) + l.Bridge.Connected = false + l.Bridge.Client = nil + l.Bridge.MumbleUserCount = 0 + l.Bridge.MumbleUsers = make(map[string]bool) + l.Bridge.DiscordUserCount = 0 + l.Bridge.DiscordUsers = make(map[string]bool) } } -func discordStatusUpdate(dg *discordgo.Session, host, port string) { +func discordStatusUpdate(dg *discordgo.Session, host, port string, l *Listener) { status := "" curr := 0 m, _ := time.ParseDuration("30s") @@ -153,17 +154,17 @@ func discordStatusUpdate(dg *discordgo.Session, host, port string) { dg.UpdateListeningStatus("an error pinging mumble") } else { curr = resp.ConnectedUsers - if Bridge.Connected { + if l.Bridge.Connected { curr = curr - 1 } - if curr != Bridge.MumbleUserCount { - Bridge.MumbleUserCount = curr + if curr != l.Bridge.MumbleUserCount { + l.Bridge.MumbleUserCount = curr } if curr == 0 { status = "" } else { - if len(Bridge.MumbleUsers) > 0 { - status = fmt.Sprintf("%v/%v users in Mumble\n", len(Bridge.MumbleUsers), curr) + if len(l.Bridge.MumbleUsers) > 0 { + status = fmt.Sprintf("%v/%v users in Mumble\n", len(l.Bridge.MumbleUsers), curr) } else { status = fmt.Sprintf("%v users in Mumble\n", curr) } @@ -178,20 +179,20 @@ func AutoBridge(s *discordgo.Session, l *Listener) { for { select { default: - case <-Bridge.AutoChan: + case <-l.Bridge.AutoChan: log.Println("ending automode") return } time.Sleep(3 * time.Second) - if !Bridge.Connected && Bridge.MumbleUserCount > 0 && Bridge.DiscordUserCount > 0 { + 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) - Bridge.ActiveConn = die - go startBridge(s, BridgeConf.GID, BridgeConf.CID, l, die) + l.Bridge.ActiveConn = die + go startBridge(s, l.BridgeConf.GID, l.BridgeConf.CID, l, die) } - if Bridge.Connected && Bridge.MumbleUserCount == 0 && Bridge.DiscordUserCount <= 1 { + if l.Bridge.Connected && l.Bridge.MumbleUserCount == 0 && l.Bridge.DiscordUserCount <= 1 { log.Println("no one online, killing bridge") - Bridge.ActiveConn <- true + l.Bridge.ActiveConn <- true MumbleReset() DiscordReset() } diff --git a/handlers.go b/handlers.go index 2d0b4b1..d84df61 100644 --- a/handlers.go +++ b/handlers.go @@ -145,27 +145,27 @@ func (l *Listener) guildCreate(s *discordgo.Session, event *discordgo.GuildCreat } func (l *Listener) voiceUpdate(s *discordgo.Session, event *discordgo.VoiceStateUpdate) { - if event.GuildID == BridgeConf.GID { - if event.ChannelID == BridgeConf.CID { + if event.GuildID == l.BridgeConf.GID { + if event.ChannelID == l.BridgeConf.CID { //get user u, err := s.User(event.UserID) if err != nil { log.Printf("error looking up user for uid %v", event.UserID) } //check to see if actually new user - if Bridge.DiscordUsers[u.Username] { + if l.Bridge.DiscordUsers[u.Username] { //not actually new user return } log.Println("user joined watched discord channel") - if Bridge.Connected { - Bridge.Client.Do(func() { - Bridge.Client.Self.Channel.Send(fmt.Sprintf("%v has joined Discord channel\n", u.Username), false) + 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) }) } - Bridge.DiscordUsers[u.Username] = true - log.Println(Bridge.DiscordUsers) - Bridge.DiscordUserCount = Bridge.DiscordUserCount + 1 + l.Bridge.DiscordUsers[u.Username] = true + log.Println(l.Bridge.DiscordUsers) + l.Bridge.DiscordUserCount = l.Bridge.DiscordUserCount + 1 } if event.ChannelID == "" { //leave event, trigger recount of active users @@ -179,23 +179,23 @@ func (l *Listener) voiceUpdate(s *discordgo.Session, event *discordgo.VoiceState // Look for current voice states in watched channel count := 0 for _, vs := range g.VoiceStates { - if vs.ChannelID == BridgeConf.CID { + if vs.ChannelID == l.BridgeConf.CID { count = count + 1 } } - if Bridge.DiscordUserCount > count { + if l.Bridge.DiscordUserCount > count { u, err := s.User(event.UserID) if err != nil { log.Printf("error looking up user for uid %v", event.UserID) } - delete(Bridge.DiscordUsers, u.Username) + delete(l.Bridge.DiscordUsers, u.Username) log.Println("user left watched discord channel") - if Bridge.Connected { - Bridge.Client.Do(func() { - Bridge.Client.Self.Channel.Send(fmt.Sprintf("%v has left Discord channel\n", u.Username), false) + 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) }) } - Bridge.DiscordUserCount = count + l.Bridge.DiscordUserCount = count } } @@ -206,7 +206,7 @@ func (l *Listener) voiceUpdate(s *discordgo.Session, event *discordgo.VoiceState func (l *Listener) mumbleConnect(e *gumble.ConnectEvent) { if l.BridgeConf.MumbleChannel != "" { //join specified channel - startingChannel := e.Client.Channels.Find(BridgeConf.MumbleChannel) + startingChannel := e.Client.Channels.Find(l.BridgeConf.MumbleChannel) if startingChannel != nil { e.Client.Self.Move(startingChannel) } @@ -215,7 +215,7 @@ func (l *Listener) mumbleConnect(e *gumble.ConnectEvent) { func (l *Listener) mumbleUserChange(e *gumble.UserChangeEvent) { if e.Type.Has(gumble.UserChangeConnected) || e.Type.Has(gumble.UserChangeChannel) || e.Type.Has(gumble.UserChangeDisconnected) { - Bridge.MumbleUsers = make(map[string]bool) + l.Bridge.MumbleUsers = make(map[string]bool) for _, user := range l.Bridge.Client.Self.Channel.Users { //note, this might be too slow for really really big channels? //event listeners block while processing diff --git a/main.go b/main.go index 597de55..6687c72 100644 --- a/main.go +++ b/main.go @@ -15,9 +15,6 @@ import ( _ "layeh.com/gumble/opus" ) -var BridgeConf *BridgeConfig -var Bridge *BridgeState - func main() { godotenv.Load() @@ -73,7 +70,7 @@ func main() { config.AudioInterval = time.Millisecond * 10 // Bridge setup - BridgeConf = &BridgeConfig{ + BridgeConf := &BridgeConfig{ Config: config, MumbleAddr: *mumbleAddr + ":" + strconv.Itoa(*mumblePort), MumbleInsecure: *mumbleInsecure, @@ -83,7 +80,7 @@ func main() { GID: *discordGID, CID: *discordCID, } - Bridge = &BridgeState{ + Bridge := &BridgeState{ ActiveConn: make(chan bool), Connected: false, MumbleUserCount: 0, @@ -130,7 +127,7 @@ func main() { log.Fatalln("invalid bridge mode set") } - go discordStatusUpdate(discord, *mumbleAddr, strconv.Itoa(*mumblePort)) + go discordStatusUpdate(discord, *mumbleAddr, strconv.Itoa(*mumblePort), l) sc := make(chan os.Signal, 1) signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) <-sc From f4cc9498cb4a5da585e51e9c7b8ad41acc4de831 Mon Sep 17 00:00:00 2001 From: Steve Date: Wed, 6 Jan 2021 19:12:56 -0500 Subject: [PATCH 4/4] add mutexs to prevent data races, re-organize a bit --- bridge.go | 35 ++++++++++------------------------- config.go | 1 - handlers.go | 50 ++++++++++++++++++++++++++++++++++++++++++++------ main.go | 18 +++++++++++++----- 4 files changed, 67 insertions(+), 37 deletions(-) diff --git a/bridge.go b/bridge.go index 5c2522d..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,27 +97,9 @@ func startBridge(discord *discordgo.Session, discordGID string, discordCID strin } } }() - - //Setup initial discord state - g, err := discord.State.Guild(discordGID) - if err != nil { - log.Println("error finding guild") - panic(err) - } - for _, vs := range g.VoiceStates { - if vs.ChannelID == discordCID { - l.Bridge.DiscordUserCount = l.Bridge.DiscordUserCount + 1 - u, err := discord.User(vs.UserID) - if err != nil { - log.Println("error looking up username") - l.Bridge.DiscordUsers[u.Username] = true - l.Bridge.Client.Do(func() { - l.Bridge.Client.Self.Channel.Send(fmt.Sprintf("%v has joined Discord channel\n", u.Username), false) - }) - } - } - } + l.ConnectedLock.Lock() l.Bridge.Connected = true + l.ConnectedLock.Unlock() select { case sig := <-c: @@ -153,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 @@ -169,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) } } @@ -184,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) @@ -196,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 d84df61..d7c72c0 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,17 +183,21 @@ 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 log.Println(l.Bridge.DiscordUsers) l.Bridge.DiscordUserCount = l.Bridge.DiscordUserCount + 1 + l.UserCountLock.Unlock() } if event.ChannelID == "" { //leave event, trigger recount of active users @@ -173,6 +205,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 } @@ -190,12 +223,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() } } @@ -214,6 +250,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 { @@ -225,4 +262,5 @@ func (l *Listener) mumbleUserChange(e *gumble.UserChangeEvent) { } } } + l.UserCountLock.Unlock() } diff --git a/main.go b/main.go index 6687c72..36e10d2 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()