mirror of
https://github.com/stryan/mumble-discord-bridge.git
synced 2024-11-22 21:35:44 -05:00
send messages between mumble and discord when users connect/disconnect
This commit is contained in:
parent
5f9ad7b7dd
commit
cbd6d19066
102
discord.go
102
discord.go
@ -18,10 +18,19 @@ type fromDiscord struct {
|
|||||||
streaming bool
|
streaming bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type discordUser struct {
|
||||||
|
username string
|
||||||
|
seen bool
|
||||||
|
dm *discordgo.Channel
|
||||||
|
}
|
||||||
|
|
||||||
var discordMutex sync.Mutex
|
var discordMutex sync.Mutex
|
||||||
var discordMixerMutex sync.Mutex
|
var discordMixerMutex sync.Mutex
|
||||||
var fromDiscordMap = make(map[uint32]fromDiscord)
|
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.
|
// OnError gets called by dgvoice when an error is encountered.
|
||||||
// By default logs to STDERR
|
// By default logs to STDERR
|
||||||
var OnError = func(str string, err error) {
|
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
24
main.go
@ -25,6 +25,11 @@ var (
|
|||||||
date string
|
date string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
discordGID *string
|
||||||
|
discordCID *string
|
||||||
|
)
|
||||||
|
|
||||||
func lookupEnvOrString(key string, defaultVal string) string {
|
func lookupEnvOrString(key string, defaultVal string) string {
|
||||||
if val, ok := os.LookupEnv(key); ok {
|
if val, ok := os.LookupEnv(key); ok {
|
||||||
return val
|
return val
|
||||||
@ -71,13 +76,13 @@ func main() {
|
|||||||
|
|
||||||
mumbleAddr := flag.String("mumble-address", lookupEnvOrString("MUMBLE_ADDRESS", ""), "MUMBLE_ADDRESS, mumble server address, example example.com")
|
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")
|
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")
|
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")
|
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")
|
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")
|
discordGID = flag.String("discord-gid", lookupEnvOrString("DISCORD_GID", ""), "DISCORD_GID, discord gid")
|
||||||
discordCID := flag.String("discord-cid", lookupEnvOrString("DISCORD_CID", ""), "DISCORD_CID, discord cid")
|
discordCID = flag.String("discord-cid", lookupEnvOrString("DISCORD_CID", ""), "DISCORD_CID, discord cid")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
log.Printf("app.config %v\n", getConfig(flag.CommandLine))
|
log.Printf("app.config %v\n", getConfig(flag.CommandLine))
|
||||||
@ -116,7 +121,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Open Websocket
|
// Open Websocket
|
||||||
|
discord.ShouldReconnectOnError = true
|
||||||
discord.LogLevel = 1
|
discord.LogLevel = 1
|
||||||
|
discord.StateEnabled = true
|
||||||
|
discord.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAllWithoutPrivileged)
|
||||||
|
|
||||||
err = discord.Open()
|
err = discord.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
@ -134,8 +143,6 @@ func main() {
|
|||||||
defer dgv.Speaking(false)
|
defer dgv.Speaking(false)
|
||||||
defer dgv.Close()
|
defer dgv.Close()
|
||||||
|
|
||||||
discord.ShouldReconnectOnError = true
|
|
||||||
|
|
||||||
// MUMBLE Setup
|
// MUMBLE Setup
|
||||||
|
|
||||||
config := gumble.NewConfig()
|
config := gumble.NewConfig()
|
||||||
@ -144,7 +151,9 @@ func main() {
|
|||||||
config.AudioInterval = time.Millisecond * 10
|
config.AudioInterval = time.Millisecond * 10
|
||||||
|
|
||||||
m := MumbleDuplex{}
|
m := MumbleDuplex{}
|
||||||
ml := MumbleEventListener{}
|
ml := MumbleEventListener{
|
||||||
|
d: discord,
|
||||||
|
}
|
||||||
|
|
||||||
var tlsConfig tls.Config
|
var tlsConfig tls.Config
|
||||||
if *mumbleInsecure {
|
if *mumbleInsecure {
|
||||||
@ -167,6 +176,8 @@ func main() {
|
|||||||
|
|
||||||
log.Println("Mumble Connected")
|
log.Println("Mumble Connected")
|
||||||
|
|
||||||
|
// Initial User States
|
||||||
|
|
||||||
// Start Passing Between
|
// Start Passing Between
|
||||||
// Mumble
|
// Mumble
|
||||||
go m.fromMumbleMixer(toDiscord)
|
go m.fromMumbleMixer(toDiscord)
|
||||||
@ -176,6 +187,7 @@ func main() {
|
|||||||
go discordReceivePCM(dgv, die)
|
go discordReceivePCM(dgv, die)
|
||||||
go fromDiscordMixer(toMumble)
|
go fromDiscordMixer(toMumble)
|
||||||
go discordSendPCM(dgv, toDiscord, die)
|
go discordSendPCM(dgv, toDiscord, die)
|
||||||
|
go discordMemberWatcher(discord, mumble)
|
||||||
|
|
||||||
// Wait for Exit Signal
|
// Wait for Exit Signal
|
||||||
c := make(chan os.Signal)
|
c := make(chan os.Signal)
|
||||||
|
@ -2,13 +2,17 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
"layeh.com/gumble/gumble"
|
"layeh.com/gumble/gumble"
|
||||||
_ "layeh.com/gumble/opus"
|
_ "layeh.com/gumble/opus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MumbleEventListener - Bridge Event Handler
|
// MumbleEventListener - Bridge Event Handler
|
||||||
type MumbleEventListener struct{}
|
type MumbleEventListener struct {
|
||||||
|
d *discordgo.Session
|
||||||
|
}
|
||||||
|
|
||||||
// OnConnect - event handler
|
// OnConnect - event handler
|
||||||
func (ml MumbleEventListener) OnConnect(e *gumble.ConnectEvent) {
|
func (ml MumbleEventListener) OnConnect(e *gumble.ConnectEvent) {
|
||||||
@ -28,6 +32,33 @@ func (ml MumbleEventListener) OnTextMessage(e *gumble.TextMessageEvent) {
|
|||||||
// OnUserChange - event handler
|
// OnUserChange - event handler
|
||||||
func (ml MumbleEventListener) OnUserChange(e *gumble.UserChangeEvent) {
|
func (ml MumbleEventListener) OnUserChange(e *gumble.UserChangeEvent) {
|
||||||
fmt.Println("OnUserChange", e.User.Name, e)
|
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
|
// OnChannelChange - event handler
|
||||||
|
Loading…
Reference in New Issue
Block a user