1
0
mirror of https://github.com/stryan/mumble-discord-bridge.git synced 2024-12-28 17:15:40 -05:00

send messages between mumble and discord when users connect/disconnect

This commit is contained in:
Tyler Stiene 2021-01-13 00:41:22 -05:00
parent 5f9ad7b7dd
commit cbd6d19066
3 changed files with 152 additions and 7 deletions

View File

@ -18,10 +18,19 @@ type fromDiscord struct {
streaming bool
}
type discordUser struct {
username string
seen bool
dm *discordgo.Channel
}
var discordMutex sync.Mutex
var discordMixerMutex sync.Mutex
var fromDiscordMap = make(map[uint32]fromDiscord)
var discordUsersMutex sync.Mutex
var discordUsers = make(map[string]discordUser) // id is the key
// OnError gets called by dgvoice when an error is encountered.
// By default logs to STDERR
var OnError = func(str string, err error) {
@ -227,3 +236,96 @@ func fromDiscordMixer(toMumble chan<- gumble.AudioBuffer) {
}
}
}
// This function acts a filter from the interall discordgo state the local state
// This function
func discordMemberWatcher(d *discordgo.Session, m *gumble.Client) {
ticker := time.NewTicker(250 * time.Millisecond)
g, err := d.State.Guild(*discordGID)
if err != nil {
log.Println("error finding guild")
panic(err)
}
// Watch Discordgo internal state for member changes in the channel
for {
<-ticker.C
discordUsersMutex.Lock()
// start := time.Now()
// Set all members to false
for u := range discordUsers {
du := discordUsers[u]
du.seen = false
discordUsers[u] = du
}
// Sync the channel voice states to the local discordUsersMap
for _, vs := range g.VoiceStates {
if vs.ChannelID == *discordCID {
if d.State.User.ID == vs.UserID {
continue
}
if _, ok := discordUsers[vs.UserID]; !ok {
u, err := d.User(vs.UserID)
if err != nil {
log.Println("error looking up username")
continue
}
println("User joined Discord " + u.Username)
dm, err := d.UserChannelCreate(u.ID)
if err != nil {
log.Panicln("Error creating private channel for", u.Username)
}
discordUsers[vs.UserID] = discordUser{
username: u.Username,
seen: true,
dm: dm,
}
m.Do(func() {
m.Self.Channel.Send(fmt.Sprintf("%v has joined Discord\n", u.Username), false)
})
} else {
du := discordUsers[vs.UserID]
du.seen = true
discordUsers[vs.UserID] = du
}
}
}
// Remove users that are no longer connected
for id := range discordUsers {
if discordUsers[id].seen == false {
println("User left Discord channel " + discordUsers[id].username)
m.Do(func() {
m.Self.Channel.Send(fmt.Sprintf("%v has left Discord channel\n", discordUsers[id].username), false)
})
delete(discordUsers, id)
}
}
discordUsersMutex.Unlock()
// elapsed := time.Since(start)
// log.Printf("Discord user sync took %s", elapsed)
}
}
func discordSendMessageAll(d *discordgo.Session, msg string) {
discordUsersMutex.Lock()
for id := range discordUsers {
du := discordUsers[id]
if du.dm != nil {
log.Println("Sensing msg to ")
d.ChannelMessageSend(du.dm.ID, msg)
}
}
discordUsersMutex.Unlock()
}

24
main.go
View File

@ -25,6 +25,11 @@ var (
date string
)
var (
discordGID *string
discordCID *string
)
func lookupEnvOrString(key string, defaultVal string) string {
if val, ok := os.LookupEnv(key); ok {
return val
@ -71,13 +76,13 @@ func main() {
mumbleAddr := flag.String("mumble-address", lookupEnvOrString("MUMBLE_ADDRESS", ""), "MUMBLE_ADDRESS, mumble server address, example example.com")
mumblePort := flag.Int("mumble-port", lookupEnvOrInt("MUMBLE_PORT", 64738), "MUMBLE_PORT mumble port")
mumbleUsername := flag.String("mumble-username", lookupEnvOrString("MUMBLE_USERNAME", "discord-bridge"), "MUMBLE_USERNAME, mumble username")
mumbleUsername := flag.String("mumble-username", lookupEnvOrString("MUMBLE_USERNAME", "discord"), "MUMBLE_USERNAME, mumble username")
mumblePassword := flag.String("mumble-password", lookupEnvOrString("MUMBLE_PASSWORD", ""), "MUMBLE_PASSWORD, mumble password, optional")
mumbleInsecure := flag.Bool("mumble-insecure", lookupEnvOrBool("MUMBLE_INSECURE", false), "mumble insecure, env alt MUMBLE_INSECURE")
discordToken := flag.String("discord-token", lookupEnvOrString("DISCORD_TOKEN", ""), "DISCORD_TOKEN, discord bot token")
discordGID := flag.String("discord-gid", lookupEnvOrString("DISCORD_GID", ""), "DISCORD_GID, discord gid")
discordCID := flag.String("discord-cid", lookupEnvOrString("DISCORD_CID", ""), "DISCORD_CID, discord cid")
discordGID = flag.String("discord-gid", lookupEnvOrString("DISCORD_GID", ""), "DISCORD_GID, discord gid")
discordCID = flag.String("discord-cid", lookupEnvOrString("DISCORD_CID", ""), "DISCORD_CID, discord cid")
flag.Parse()
log.Printf("app.config %v\n", getConfig(flag.CommandLine))
@ -116,7 +121,11 @@ func main() {
}
// Open Websocket
discord.ShouldReconnectOnError = true
discord.LogLevel = 1
discord.StateEnabled = true
discord.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAllWithoutPrivileged)
err = discord.Open()
if err != nil {
log.Println(err)
@ -134,8 +143,6 @@ func main() {
defer dgv.Speaking(false)
defer dgv.Close()
discord.ShouldReconnectOnError = true
// MUMBLE Setup
config := gumble.NewConfig()
@ -144,7 +151,9 @@ func main() {
config.AudioInterval = time.Millisecond * 10
m := MumbleDuplex{}
ml := MumbleEventListener{}
ml := MumbleEventListener{
d: discord,
}
var tlsConfig tls.Config
if *mumbleInsecure {
@ -167,6 +176,8 @@ func main() {
log.Println("Mumble Connected")
// Initial User States
// Start Passing Between
// Mumble
go m.fromMumbleMixer(toDiscord)
@ -176,6 +187,7 @@ func main() {
go discordReceivePCM(dgv, die)
go fromDiscordMixer(toMumble)
go discordSendPCM(dgv, toDiscord, die)
go discordMemberWatcher(discord, mumble)
// Wait for Exit Signal
c := make(chan os.Signal)

View File

@ -2,13 +2,17 @@ package main
import (
"fmt"
"strings"
"github.com/bwmarrin/discordgo"
"layeh.com/gumble/gumble"
_ "layeh.com/gumble/opus"
)
// MumbleEventListener - Bridge Event Handler
type MumbleEventListener struct{}
type MumbleEventListener struct {
d *discordgo.Session
}
// OnConnect - event handler
func (ml MumbleEventListener) OnConnect(e *gumble.ConnectEvent) {
@ -28,6 +32,33 @@ func (ml MumbleEventListener) OnTextMessage(e *gumble.TextMessageEvent) {
// OnUserChange - event handler
func (ml MumbleEventListener) OnUserChange(e *gumble.UserChangeEvent) {
fmt.Println("OnUserChange", e.User.Name, e)
if e.Type.Has(gumble.UserChangeConnected) {
e.User.Send("Mumble-Discord-Bridge v" + version)
// Tell the user who is connected to discord
if len(discordUsers) == 0 {
e.User.Send("No users connected to Discord")
} else {
s := "Users connected to Discord: "
arr := []string{}
discordUsersMutex.Lock()
for u := range discordUsers {
arr = append(arr, u)
}
s = s + strings.Join(arr[:], ",")
discordUsersMutex.Unlock()
e.User.Send(s)
}
// Send discord a notice
discordSendMessageAll(ml.d, e.User.Name+" has joined mumble")
}
if e.Type.Has(gumble.UserChangeDisconnected) {
discordSendMessageAll(ml.d, e.User.Name+" has left mumble")
}
}
// OnChannelChange - event handler