mirror of
https://github.com/stryan/mumble-discord-bridge.git
synced 2024-12-27 17:05:40 -05:00
restrucutre into go standard folder strucutre
This commit is contained in:
parent
5bc118c97c
commit
a963d2caa1
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,7 +2,6 @@
|
||||
main
|
||||
mumble-discord-bridge
|
||||
dist
|
||||
bridge
|
||||
*.prof
|
||||
*.out
|
||||
*.test
|
||||
|
2
Makefile
2
Makefile
@ -1,4 +1,4 @@
|
||||
GOFILES=main.go mumble.go discord.go bridge.go config.go mumble-handlers.go discord-handlers.go sleepct.go
|
||||
GOFILES=$(shell find ./ -type f -name '*.go')
|
||||
|
||||
mumble-discord-bridge: $(GOFILES)
|
||||
goreleaser build --skip-validate --rm-dist
|
||||
|
74
config.go
74
config.go
@ -1,74 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"layeh.com/gumble/gumble"
|
||||
)
|
||||
|
||||
type bridgeMode int
|
||||
|
||||
const (
|
||||
bridgeModeAuto bridgeMode = iota
|
||||
bridgeModeManual
|
||||
bridgeModeConstant
|
||||
)
|
||||
|
||||
//BridgeConfig holds configuration information set at startup
|
||||
//It should not change during runtime
|
||||
type BridgeConfig struct {
|
||||
MumbleConfig *gumble.Config
|
||||
MumbleAddr string
|
||||
MumbleInsecure bool
|
||||
MumbleCertificate string
|
||||
MumbleChannel []string
|
||||
mumbleStartStreamCount int
|
||||
MumbleDisableText bool
|
||||
Command string
|
||||
GID string
|
||||
CID string
|
||||
DiscordStartStreamingCount int
|
||||
DiscordDisableText bool
|
||||
}
|
||||
|
||||
func lookupEnvOrString(key string, defaultVal string) string {
|
||||
if val, ok := os.LookupEnv(key); ok {
|
||||
return val
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
func lookupEnvOrInt(key string, defaultVal int) int {
|
||||
if val, ok := os.LookupEnv(key); ok {
|
||||
v, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
log.Fatalf("LookupEnvOrInt[%s]: %v", key, err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
func lookupEnvOrBool(key string, defaultVal bool) bool {
|
||||
if val, ok := os.LookupEnv(key); ok {
|
||||
v, err := strconv.ParseBool(val)
|
||||
if err != nil {
|
||||
log.Fatalf("LookupEnvOrInt[%s]: %v", key, err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
func getConfig(fs *flag.FlagSet) []string {
|
||||
cfg := make([]string, 0, 10)
|
||||
fs.VisitAll(func(f *flag.Flag) {
|
||||
cfg = append(cfg, fmt.Sprintf("%s:%q", f.Name, f.Value.String()))
|
||||
})
|
||||
|
||||
return cfg
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -15,12 +15,36 @@ import (
|
||||
"layeh.com/gumble/gumble"
|
||||
)
|
||||
|
||||
type discordUser struct {
|
||||
type DiscordUser struct {
|
||||
username string
|
||||
seen bool
|
||||
dm *discordgo.Channel
|
||||
}
|
||||
|
||||
type BridgeMode int
|
||||
|
||||
const (
|
||||
BridgeModeAuto BridgeMode = iota
|
||||
BridgeModeManual
|
||||
BridgeModeConstant
|
||||
)
|
||||
|
||||
type BridgeConfig struct {
|
||||
MumbleConfig *gumble.Config
|
||||
MumbleAddr string
|
||||
MumbleInsecure bool
|
||||
MumbleCertificate string
|
||||
MumbleChannel []string
|
||||
MumbleStartStreamCount int
|
||||
MumbleDisableText bool
|
||||
Command string
|
||||
GID string
|
||||
CID string
|
||||
DiscordStartStreamingCount int
|
||||
DiscordDisableText bool
|
||||
Version string
|
||||
}
|
||||
|
||||
//BridgeState manages dynamic information about the bridge during runtime
|
||||
type BridgeState struct {
|
||||
// The configuration data for this bridge
|
||||
@ -42,7 +66,7 @@ type BridgeState struct {
|
||||
Connected bool
|
||||
|
||||
// The bridge mode constant, auto, manual. Default is constant.
|
||||
Mode bridgeMode
|
||||
Mode BridgeMode
|
||||
|
||||
// Discord session. This is created and outside the bridge state
|
||||
DiscordSession *discordgo.Session
|
||||
@ -54,7 +78,7 @@ type BridgeState struct {
|
||||
MumbleClient *gumble.Client
|
||||
|
||||
// Map of Discord users tracked by this bridge.
|
||||
DiscordUsers map[string]discordUser
|
||||
DiscordUsers map[string]DiscordUser
|
||||
DiscordUsersMutex sync.Mutex
|
||||
|
||||
// Map of Mumble users tracked by this bridge
|
||||
@ -80,7 +104,7 @@ type BridgeState struct {
|
||||
}
|
||||
|
||||
// startBridge established the voice connection
|
||||
func (b *BridgeState) startBridge() {
|
||||
func (b *BridgeState) StartBridge() {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
@ -214,10 +238,10 @@ func (b *BridgeState) startBridge() {
|
||||
b.MumbleUsersMutex.Lock()
|
||||
b.MumbleUsers = make(map[string]bool)
|
||||
b.MumbleUsersMutex.Unlock()
|
||||
b.DiscordUsers = make(map[string]discordUser)
|
||||
b.DiscordUsers = make(map[string]DiscordUser)
|
||||
}
|
||||
|
||||
func (b *BridgeState) discordStatusUpdate() {
|
||||
func (b *BridgeState) DiscordStatusUpdate() {
|
||||
m, _ := time.ParseDuration("30s")
|
||||
for {
|
||||
time.Sleep(3 * time.Second)
|
||||
@ -254,14 +278,14 @@ func (b *BridgeState) discordStatusUpdate() {
|
||||
// when there is at least one user on both, starts up the bridge
|
||||
// when there are no users on either side, kills the bridge
|
||||
func (b *BridgeState) AutoBridge() {
|
||||
log.Println("beginning auto mode")
|
||||
log.Println("Beginning auto mode")
|
||||
ticker := time.NewTicker(3 * time.Second)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
case <-b.AutoChanDie:
|
||||
log.Println("ending automode")
|
||||
log.Println("Ending automode")
|
||||
return
|
||||
}
|
||||
|
||||
@ -270,11 +294,11 @@ func (b *BridgeState) AutoBridge() {
|
||||
b.BridgeMutex.Lock()
|
||||
|
||||
if !b.Connected && b.MumbleUserCount > 0 && len(b.DiscordUsers) > 0 {
|
||||
log.Println("users detected in mumble and discord, bridging")
|
||||
go b.startBridge()
|
||||
log.Println("Users detected in mumble and discord, bridging")
|
||||
go b.StartBridge()
|
||||
}
|
||||
if b.Connected && b.MumbleUserCount == 0 && len(b.DiscordUsers) <= 1 {
|
||||
log.Println("no one online, killing bridge")
|
||||
log.Println("No one online, killing bridge")
|
||||
b.BridgeDie <- true
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -15,11 +15,11 @@ type DiscordListener struct {
|
||||
Bridge *BridgeState
|
||||
}
|
||||
|
||||
func (l *DiscordListener) guildCreate(s *discordgo.Session, event *discordgo.GuildCreate) {
|
||||
func (l *DiscordListener) GuildCreate(s *discordgo.Session, event *discordgo.GuildCreate) {
|
||||
log.Println("CREATE event registered")
|
||||
|
||||
if event.ID != l.Bridge.BridgeConfig.GID {
|
||||
log.Println("received GuildCreate from a guild not in config")
|
||||
log.Println("Received GuildCreate from a guild not in config")
|
||||
return
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ func (l *DiscordListener) guildCreate(s *discordgo.Session, event *discordgo.Gui
|
||||
|
||||
u, err := s.User(vs.UserID)
|
||||
if err != nil {
|
||||
log.Println("error looking up username")
|
||||
log.Println("Error looking up username")
|
||||
}
|
||||
|
||||
dm, err := s.UserChannelCreate(u.ID)
|
||||
@ -41,7 +41,7 @@ func (l *DiscordListener) guildCreate(s *discordgo.Session, event *discordgo.Gui
|
||||
}
|
||||
|
||||
l.Bridge.DiscordUsersMutex.Lock()
|
||||
l.Bridge.DiscordUsers[vs.UserID] = discordUser{
|
||||
l.Bridge.DiscordUsers[vs.UserID] = DiscordUser{
|
||||
username: u.Username,
|
||||
seen: true,
|
||||
dm: dm,
|
||||
@ -61,7 +61,7 @@ func (l *DiscordListener) guildCreate(s *discordgo.Session, event *discordgo.Gui
|
||||
}
|
||||
}
|
||||
|
||||
func (l *DiscordListener) messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
func (l *DiscordListener) MessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
|
||||
// Ignore all messages created by the bot itself
|
||||
if m.Author.ID == s.State.User.ID {
|
||||
@ -82,7 +82,7 @@ func (l *DiscordListener) messageCreate(s *discordgo.Session, m *discordgo.Messa
|
||||
}
|
||||
prefix := "!" + l.Bridge.BridgeConfig.Command
|
||||
|
||||
if l.Bridge.Mode == bridgeModeConstant && strings.HasPrefix(m.Content, prefix) {
|
||||
if l.Bridge.Mode == BridgeModeConstant && strings.HasPrefix(m.Content, prefix) {
|
||||
l.Bridge.DiscordSession.ChannelMessageSend(m.ChannelID, "Constant mode enabled, manual commands can not be entered")
|
||||
return
|
||||
}
|
||||
@ -101,7 +101,7 @@ func (l *DiscordListener) messageCreate(s *discordgo.Session, m *discordgo.Messa
|
||||
if vs.UserID == m.Author.ID {
|
||||
log.Printf("Trying to join GID %v and VID %v\n", g.ID, vs.ChannelID)
|
||||
l.Bridge.DiscordChannelID = vs.ChannelID
|
||||
go l.Bridge.startBridge()
|
||||
go l.Bridge.StartBridge()
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -135,16 +135,16 @@ func (l *DiscordListener) messageCreate(s *discordgo.Session, m *discordgo.Messa
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
go l.Bridge.startBridge()
|
||||
go l.Bridge.StartBridge()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(m.Content, prefix+" auto") {
|
||||
if l.Bridge.Mode != bridgeModeAuto {
|
||||
if l.Bridge.Mode != BridgeModeAuto {
|
||||
l.Bridge.DiscordSession.ChannelMessageSend(m.ChannelID, "Auto mode enabled")
|
||||
l.Bridge.Mode = bridgeModeAuto
|
||||
l.Bridge.Mode = BridgeModeAuto
|
||||
l.Bridge.DiscordChannelID = l.Bridge.BridgeConfig.CID
|
||||
l.Bridge.AutoChanDie = make(chan bool)
|
||||
go l.Bridge.AutoBridge()
|
||||
@ -152,12 +152,12 @@ func (l *DiscordListener) messageCreate(s *discordgo.Session, m *discordgo.Messa
|
||||
l.Bridge.DiscordSession.ChannelMessageSend(m.ChannelID, "Auto mode disabled")
|
||||
l.Bridge.DiscordChannelID = ""
|
||||
l.Bridge.AutoChanDie <- true
|
||||
l.Bridge.Mode = bridgeModeManual
|
||||
l.Bridge.Mode = BridgeModeManual
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *DiscordListener) voiceUpdate(s *discordgo.Session, event *discordgo.VoiceStateUpdate) {
|
||||
func (l *DiscordListener) VoiceUpdate(s *discordgo.Session, event *discordgo.VoiceStateUpdate) {
|
||||
l.Bridge.DiscordUsersMutex.Lock()
|
||||
defer l.Bridge.DiscordUsersMutex.Unlock()
|
||||
|
||||
@ -165,7 +165,7 @@ func (l *DiscordListener) voiceUpdate(s *discordgo.Session, event *discordgo.Voi
|
||||
|
||||
g, err := s.State.Guild(l.Bridge.BridgeConfig.GID)
|
||||
if err != nil {
|
||||
log.Println("error finding guild")
|
||||
log.Println("Error finding guild")
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@ -187,7 +187,7 @@ func (l *DiscordListener) voiceUpdate(s *discordgo.Session, event *discordgo.Voi
|
||||
|
||||
u, err := s.User(vs.UserID)
|
||||
if err != nil {
|
||||
log.Println("error looking up username")
|
||||
log.Println("Error looking up username")
|
||||
continue
|
||||
}
|
||||
|
||||
@ -196,7 +196,7 @@ func (l *DiscordListener) voiceUpdate(s *discordgo.Session, event *discordgo.Voi
|
||||
if err != nil {
|
||||
log.Println("Error creating private channel for", u.Username)
|
||||
}
|
||||
l.Bridge.DiscordUsers[vs.UserID] = discordUser{
|
||||
l.Bridge.DiscordUsers[vs.UserID] = DiscordUser{
|
||||
username: u.Username,
|
||||
seen: true,
|
||||
dm: dm,
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/stieneee/mumble-discord-bridge/pkg/sleepct"
|
||||
"layeh.com/gopus"
|
||||
"layeh.com/gumble/gumble"
|
||||
_ "layeh.com/gumble/opus"
|
||||
@ -61,11 +62,8 @@ func (dd *DiscordDuplex) discordSendPCM(ctx context.Context, wg *sync.WaitGroup,
|
||||
opusSilence = append(opusSilence, 0x00)
|
||||
}
|
||||
|
||||
// ticker := NewTickerCT(20 * time.Millisecond)
|
||||
sleepTick := SleepCT{
|
||||
d: 20 * time.Millisecond,
|
||||
t: time.Now(),
|
||||
}
|
||||
sleepTick := sleepct.SleepCT{}
|
||||
sleepTick.Start(20 * time.Millisecond)
|
||||
|
||||
lastReady := true
|
||||
var readyTimeout *time.Timer
|
||||
@ -79,7 +77,7 @@ func (dd *DiscordDuplex) discordSendPCM(ctx context.Context, wg *sync.WaitGroup,
|
||||
if lastReady {
|
||||
OnError(fmt.Sprintf("Discordgo not ready for opus packets. %+v : %+v", dd.Bridge.DiscordVoice.Ready, dd.Bridge.DiscordVoice.OpusSend), nil)
|
||||
readyTimeout = time.AfterFunc(30*time.Second, func() {
|
||||
log.Println("set ready timeout")
|
||||
log.Println("Debug: Set ready timeout")
|
||||
cancel()
|
||||
})
|
||||
lastReady = false
|
||||
@ -164,7 +162,7 @@ func (dd *DiscordDuplex) discordReceivePCM(ctx context.Context, wg *sync.WaitGro
|
||||
if lastReady {
|
||||
OnError(fmt.Sprintf("Discordgo not to receive opus packets. %+v : %+v", dd.Bridge.DiscordVoice.Ready, dd.Bridge.DiscordVoice.OpusSend), nil)
|
||||
readyTimeout = time.AfterFunc(30*time.Second, func() {
|
||||
log.Println("set ready timeout")
|
||||
log.Println("Debug: Set ready timeout")
|
||||
cancel()
|
||||
})
|
||||
lastReady = false
|
||||
@ -225,14 +223,14 @@ func (dd *DiscordDuplex) discordReceivePCM(ctx context.Context, wg *sync.WaitGro
|
||||
select {
|
||||
case dd.fromDiscordMap[p.SSRC].pcm <- p.PCM[0:480]:
|
||||
default:
|
||||
log.Println("fromDiscordMap buffer full. Dropping packet")
|
||||
log.Println("From Discord buffer full. Dropping packet")
|
||||
dd.discordMutex.Unlock()
|
||||
continue
|
||||
}
|
||||
select {
|
||||
case dd.fromDiscordMap[p.SSRC].pcm <- p.PCM[480:960]:
|
||||
default:
|
||||
log.Println("fromDiscordMap buffer full. Dropping packet")
|
||||
log.Println("From Discord buffer full. Dropping packet")
|
||||
}
|
||||
dd.discordMutex.Unlock()
|
||||
}
|
||||
@ -244,10 +242,10 @@ func (dd *DiscordDuplex) fromDiscordMixer(ctx context.Context, wg *sync.WaitGrou
|
||||
mumbleSilence = append(mumbleSilence, 0x00)
|
||||
}
|
||||
var speakingStart time.Time
|
||||
sleepTick := SleepCT{
|
||||
d: 10 * time.Millisecond,
|
||||
t: time.Now(),
|
||||
}
|
||||
|
||||
sleepTick := sleepct.SleepCT{}
|
||||
sleepTick.Start(10 * time.Millisecond)
|
||||
|
||||
sendAudio := false
|
||||
toMumbleStreaming := false
|
||||
wg.Add(1)
|
||||
@ -271,7 +269,7 @@ func (dd *DiscordDuplex) fromDiscordMixer(ctx context.Context, wg *sync.WaitGrou
|
||||
for i := range dd.fromDiscordMap {
|
||||
bufferLength := len(dd.fromDiscordMap[i].pcm)
|
||||
isStreaming := dd.fromDiscordMap[i].streaming
|
||||
if (bufferLength > 0 && isStreaming) || (bufferLength > dd.Bridge.BridgeConfig.mumbleStartStreamCount && !isStreaming) {
|
||||
if (bufferLength > 0 && isStreaming) || (bufferLength > dd.Bridge.BridgeConfig.MumbleStartStreamCount && !isStreaming) {
|
||||
if !toMumbleStreaming {
|
||||
speakingStart = time.Now()
|
||||
toMumbleStreaming = true
|
||||
@ -307,7 +305,7 @@ func (dd *DiscordDuplex) fromDiscordMixer(ctx context.Context, wg *sync.WaitGrou
|
||||
select {
|
||||
case toMumble <- outBuf:
|
||||
case <-timeout:
|
||||
log.Println("toMumble timeout. Dropping packet")
|
||||
log.Println("To Mumble timeout. Dropping packet")
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"log"
|
||||
@ -12,7 +12,7 @@ type MumbleListener struct {
|
||||
Bridge *BridgeState
|
||||
}
|
||||
|
||||
func (l *MumbleListener) mumbleConnect(e *gumble.ConnectEvent) {
|
||||
func (l *MumbleListener) MumbleConnect(e *gumble.ConnectEvent) {
|
||||
//join specified channel
|
||||
startingChannel := e.Client.Channels.Find(l.Bridge.BridgeConfig.MumbleChannel...)
|
||||
if startingChannel != nil {
|
||||
@ -20,7 +20,7 @@ func (l *MumbleListener) mumbleConnect(e *gumble.ConnectEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
func (l *MumbleListener) mumbleUserChange(e *gumble.UserChangeEvent) {
|
||||
func (l *MumbleListener) MumbleUserChange(e *gumble.UserChangeEvent) {
|
||||
l.Bridge.MumbleUsersMutex.Lock()
|
||||
if e.Type.Has(gumble.UserChangeConnected) || e.Type.Has(gumble.UserChangeChannel) || e.Type.Has(gumble.UserChangeDisconnected) {
|
||||
l.Bridge.MumbleUsers = make(map[string]bool)
|
||||
@ -40,7 +40,7 @@ func (l *MumbleListener) mumbleUserChange(e *gumble.UserChangeEvent) {
|
||||
log.Println("User connected to mumble " + e.User.Name)
|
||||
|
||||
if !l.Bridge.BridgeConfig.MumbleDisableText {
|
||||
e.User.Send("Mumble-Discord-Bridge v" + version)
|
||||
e.User.Send("Mumble-Discord-Bridge v" + l.Bridge.BridgeConfig.Version)
|
||||
|
||||
// Tell the user who is connected to discord
|
||||
l.Bridge.DiscordUsersMutex.Lock()
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/stieneee/mumble-discord-bridge/pkg/sleepct"
|
||||
"layeh.com/gumble/gumble"
|
||||
_ "layeh.com/gumble/opus"
|
||||
)
|
||||
@ -30,7 +31,7 @@ func (m MumbleDuplex) OnAudioStream(e *gumble.AudioStreamEvent) {
|
||||
|
||||
go func() {
|
||||
name := e.User.Name
|
||||
log.Println("new mumble audio stream", name)
|
||||
log.Println("New mumble audio stream", name)
|
||||
for p := range e.C {
|
||||
// log.Println("audio packet", p.Sender.Name, len(p.AudioBuffer))
|
||||
|
||||
@ -39,15 +40,14 @@ func (m MumbleDuplex) OnAudioStream(e *gumble.AudioStreamEvent) {
|
||||
localMumbleArray <- p.AudioBuffer[480*i : 480*(i+1)]
|
||||
}
|
||||
}
|
||||
log.Println("mumble audio stream ended", name)
|
||||
log.Println("Mumble audio stream ended", name)
|
||||
}()
|
||||
}
|
||||
|
||||
func (m MumbleDuplex) fromMumbleMixer(ctx context.Context, wg *sync.WaitGroup, toDiscord chan []int16) {
|
||||
sleepTick := SleepCT{
|
||||
d: 10 * time.Millisecond,
|
||||
t: time.Now(),
|
||||
}
|
||||
sleepTick := sleepct.SleepCT{}
|
||||
sleepTick.Start(10 * time.Millisecond)
|
||||
|
||||
sendAudio := false
|
||||
bufferWarning := false
|
||||
|
||||
@ -74,7 +74,7 @@ func (m MumbleDuplex) fromMumbleMixer(ctx context.Context, wg *sync.WaitGroup, t
|
||||
sendAudio = true
|
||||
if !mumbleStreamingArr[i] {
|
||||
mumbleStreamingArr[i] = true
|
||||
// log.Println("mumble starting", i)
|
||||
// log.Println("Mumble starting", i)
|
||||
}
|
||||
|
||||
x1 := (<-fromMumbleArr[i])
|
||||
@ -82,7 +82,7 @@ func (m MumbleDuplex) fromMumbleMixer(ctx context.Context, wg *sync.WaitGroup, t
|
||||
} else {
|
||||
if mumbleStreamingArr[i] {
|
||||
mumbleStreamingArr[i] = false
|
||||
// log.Println("mumble stopping", i)
|
||||
// log.Println("Mumble stopping", i)
|
||||
}
|
||||
}
|
||||
}
|
234
main.go
234
main.go
@ -1,234 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime/pprof"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/joho/godotenv"
|
||||
"layeh.com/gumble/gumble"
|
||||
"layeh.com/gumble/gumbleutil"
|
||||
_ "layeh.com/gumble/opus"
|
||||
)
|
||||
|
||||
var (
|
||||
// Build vars
|
||||
version string
|
||||
commit string
|
||||
date string
|
||||
)
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
|
||||
fmt.Println("Mumble-Discord-Bridge")
|
||||
fmt.Println("v" + version + " " + commit + " " + date)
|
||||
|
||||
godotenv.Load()
|
||||
|
||||
mumbleAddr := flag.String("mumble-address", lookupEnvOrString("MUMBLE_ADDRESS", ""), "MUMBLE_ADDRESS, mumble server address, example example.com, required")
|
||||
mumblePort := flag.Int("mumble-port", lookupEnvOrInt("MUMBLE_PORT", 64738), "MUMBLE_PORT, mumble port, (default 64738)")
|
||||
mumbleUsername := flag.String("mumble-username", lookupEnvOrString("MUMBLE_USERNAME", "Discord"), "MUMBLE_USERNAME, mumble username, (default: discord)")
|
||||
mumblePassword := flag.String("mumble-password", lookupEnvOrString("MUMBLE_PASSWORD", ""), "MUMBLE_PASSWORD, mumble password, optional")
|
||||
mumbleInsecure := flag.Bool("mumble-insecure", lookupEnvOrBool("MUMBLE_INSECURE", false), " MUMBLE_INSECURE, mumble insecure, optional")
|
||||
mumbleCertificate := flag.String("mumble-certificate", lookupEnvOrString("MUMBLE_CERTIFICATE", ""), "MUMBLE_CERTIFICATE, client certificate to use when connecting to the Mumble server")
|
||||
mumbleChannel := flag.String("mumble-channel", lookupEnvOrString("MUMBLE_CHANNEL", ""), "MUMBLE_CHANNEL, mumble channel to start in, using '/' to separate nested channels, optional")
|
||||
mumbleSendBuffer := flag.Int("to-mumble-buffer", lookupEnvOrInt("TO_MUMBLE_BUFFER", 50), "TO_MUMBLE_BUFFER, Jitter buffer from Discord to Mumble to absorb timing issues related to network, OS and hardware quality. (Increments of 10ms)")
|
||||
mumbleDisableText := flag.Bool("mumble-disable-text", lookupEnvOrBool("MUMBLE_DISABLE_TEXT", false), "MUMBLE_DISABLE_TEXT, disable sending text to mumble, (default false)")
|
||||
discordToken := flag.String("discord-token", lookupEnvOrString("DISCORD_TOKEN", ""), "DISCORD_TOKEN, discord bot token, required")
|
||||
discordGID := flag.String("discord-gid", lookupEnvOrString("DISCORD_GID", ""), "DISCORD_GID, discord gid, required")
|
||||
discordCID := flag.String("discord-cid", lookupEnvOrString("DISCORD_CID", ""), "DISCORD_CID, discord cid, required")
|
||||
discordSendBuffer := flag.Int("to-discord-buffer", lookupEnvOrInt("TO_DISCORD_BUFFER", 50), "TO_DISCORD_BUFFER, Jitter buffer from Mumble to Discord to absorb timing issues related to network, OS and hardware quality. (Increments of 10ms)")
|
||||
discordCommand := flag.String("discord-command", lookupEnvOrString("DISCORD_COMMAND", "mumble-discord"), "DISCORD_COMMAND, Discord command string, env alt DISCORD_COMMAND, optional, (defaults mumble-discord)")
|
||||
discordDisableText := flag.Bool("discord-disable-text", lookupEnvOrBool("DISCORD_DISABLE_TEXT", false), "DISCORD_DISABLE_TEXT, disable sending direct messages to discord, (default false)")
|
||||
mode := flag.String("mode", lookupEnvOrString("MODE", "constant"), "MODE, [constant, manual, auto] determine which mode the bridge starts in, (default constant)")
|
||||
nice := flag.Bool("nice", lookupEnvOrBool("NICE", false), "NICE, whether the bridge should automatically try to 'nice' itself, (default false)")
|
||||
debug := flag.Int("debug-level", lookupEnvOrInt("DEBUG", 1), "DEBUG_LEVEL, Discord debug level, optional, (default 1)")
|
||||
|
||||
cpuprofile := flag.String("cpuprofile", "", "write cpu profile to `file`")
|
||||
|
||||
flag.Parse()
|
||||
log.Printf("app.config %v\n", getConfig(flag.CommandLine))
|
||||
|
||||
if *mumbleAddr == "" {
|
||||
log.Fatalln("missing mumble address")
|
||||
}
|
||||
if *mumbleUsername == "" {
|
||||
log.Fatalln("missing mumble username")
|
||||
}
|
||||
|
||||
if *discordToken == "" {
|
||||
log.Fatalln("missing discord bot token")
|
||||
}
|
||||
if *discordGID == "" {
|
||||
log.Fatalln("missing discord gid")
|
||||
}
|
||||
if *discordCID == "" {
|
||||
log.Fatalln("missing discord cid")
|
||||
}
|
||||
if *mode == "" {
|
||||
log.Fatalln("missing mode set")
|
||||
}
|
||||
if *nice {
|
||||
err := syscall.Setpriority(syscall.PRIO_PROCESS, os.Getpid(), -5)
|
||||
if err != nil {
|
||||
log.Println("Unable to set priority. ", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Optional CPU Profiling
|
||||
if *cpuprofile != "" {
|
||||
f, err := os.Create(*cpuprofile)
|
||||
if err != nil {
|
||||
log.Fatal("could not create CPU profile: ", err)
|
||||
}
|
||||
defer f.Close() // error handling omitted for example
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
log.Fatal("could not start CPU profile: ", err)
|
||||
}
|
||||
defer pprof.StopCPUProfile()
|
||||
}
|
||||
|
||||
// Buffer Math
|
||||
if *discordSendBuffer < 10 {
|
||||
*discordSendBuffer = 10
|
||||
}
|
||||
|
||||
if *mumbleSendBuffer < 10 {
|
||||
*mumbleSendBuffer = 10
|
||||
}
|
||||
|
||||
var discordStartStreamingCount int = int(math.Round(float64(*discordSendBuffer) / 10.0))
|
||||
log.Println("To Discord Jitter Buffer: ", discordStartStreamingCount*10, " ms")
|
||||
|
||||
var mumbleStartStreamCount int = int(math.Round(float64(*mumbleSendBuffer) / 10.0))
|
||||
log.Println("To Mumble Jitter Buffer: ", mumbleStartStreamCount*10, " ms")
|
||||
|
||||
// BRIDGE SETUP
|
||||
|
||||
Bridge := &BridgeState{
|
||||
BridgeConfig: &BridgeConfig{
|
||||
// MumbleConfig: config,
|
||||
MumbleAddr: *mumbleAddr + ":" + strconv.Itoa(*mumblePort),
|
||||
MumbleInsecure: *mumbleInsecure,
|
||||
MumbleCertificate: *mumbleCertificate,
|
||||
MumbleChannel: strings.Split(*mumbleChannel, "/"),
|
||||
mumbleStartStreamCount: mumbleStartStreamCount,
|
||||
MumbleDisableText: *mumbleDisableText,
|
||||
Command: *discordCommand,
|
||||
GID: *discordGID,
|
||||
CID: *discordCID,
|
||||
DiscordStartStreamingCount: discordStartStreamingCount,
|
||||
DiscordDisableText: *discordDisableText,
|
||||
},
|
||||
Connected: false,
|
||||
DiscordUsers: make(map[string]discordUser),
|
||||
MumbleUsers: make(map[string]bool),
|
||||
}
|
||||
|
||||
// MUMBLE SETUP
|
||||
Bridge.BridgeConfig.MumbleConfig = gumble.NewConfig()
|
||||
Bridge.BridgeConfig.MumbleConfig.Username = *mumbleUsername
|
||||
Bridge.BridgeConfig.MumbleConfig.Password = *mumblePassword
|
||||
Bridge.BridgeConfig.MumbleConfig.AudioInterval = time.Millisecond * 10
|
||||
|
||||
Bridge.MumbleListener = &MumbleListener{
|
||||
Bridge: Bridge,
|
||||
}
|
||||
|
||||
Bridge.BridgeConfig.MumbleConfig.Attach(gumbleutil.Listener{
|
||||
Connect: Bridge.MumbleListener.mumbleConnect,
|
||||
UserChange: Bridge.MumbleListener.mumbleUserChange,
|
||||
})
|
||||
|
||||
// DISCORD SETUP
|
||||
|
||||
//Connect to discord
|
||||
Bridge.DiscordSession, err = discordgo.New("Bot " + *discordToken)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
Bridge.DiscordSession.LogLevel = *debug
|
||||
Bridge.DiscordSession.StateEnabled = true
|
||||
Bridge.DiscordSession.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAllWithoutPrivileged)
|
||||
Bridge.DiscordSession.ShouldReconnectOnError = true
|
||||
// register handlers
|
||||
Bridge.DiscordListener = &DiscordListener{
|
||||
Bridge: Bridge,
|
||||
}
|
||||
Bridge.DiscordSession.AddHandler(Bridge.DiscordListener.messageCreate)
|
||||
Bridge.DiscordSession.AddHandler(Bridge.DiscordListener.guildCreate)
|
||||
Bridge.DiscordSession.AddHandler(Bridge.DiscordListener.voiceUpdate)
|
||||
|
||||
// Open Discord websocket
|
||||
err = Bridge.DiscordSession.Open()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
defer Bridge.DiscordSession.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.AutoChanDie = make(chan bool)
|
||||
Bridge.Mode = bridgeModeAuto
|
||||
Bridge.DiscordChannelID = Bridge.BridgeConfig.CID
|
||||
go Bridge.AutoBridge()
|
||||
case "manual":
|
||||
log.Println("bridge starting in manual mode")
|
||||
Bridge.Mode = bridgeModeManual
|
||||
case "constant":
|
||||
log.Println("bridge starting in constant mode")
|
||||
Bridge.Mode = bridgeModeConstant
|
||||
Bridge.DiscordChannelID = Bridge.BridgeConfig.CID
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("Bridge paniced", r)
|
||||
}
|
||||
}()
|
||||
for {
|
||||
Bridge.startBridge()
|
||||
log.Println("Bridge died")
|
||||
time.Sleep(5 * time.Second)
|
||||
log.Println("Restarting")
|
||||
}
|
||||
}()
|
||||
default:
|
||||
Bridge.DiscordSession.Close()
|
||||
log.Fatalln("invalid bridge mode set")
|
||||
}
|
||||
|
||||
go Bridge.discordStatusUpdate()
|
||||
|
||||
// Shutdown on OS signal
|
||||
sc := make(chan os.Signal, 1)
|
||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
|
||||
<-sc
|
||||
|
||||
log.Println("OS Signal. Bot shutting down")
|
||||
|
||||
// Wait or the bridge to exit cleanly
|
||||
Bridge.BridgeMutex.Lock()
|
||||
if Bridge.Connected {
|
||||
//TODO BridgeDie occasionally panics on send to closed channel
|
||||
Bridge.BridgeDie <- true
|
||||
Bridge.WaitExit.Wait()
|
||||
}
|
||||
Bridge.BridgeMutex.Unlock()
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package sleepct
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -14,6 +14,15 @@ type SleepCT struct {
|
||||
t time.Time // last time target
|
||||
}
|
||||
|
||||
func (s *SleepCT) Start(d time.Duration) {
|
||||
if s.t.IsZero() {
|
||||
s.d = d
|
||||
s.t = time.Now()
|
||||
} else {
|
||||
panic("SleepCT already started")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SleepCT) SleepNextTarget() {
|
||||
s.Lock()
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stieneee/mumble-discord-bridge/pkg/sleepct"
|
||||
"github.com/stieneee/tickerct"
|
||||
)
|
||||
|
||||
@ -107,10 +108,8 @@ func testSleepCT(wg *sync.WaitGroup) {
|
||||
now := time.Now()
|
||||
start := now
|
||||
// start the ticker
|
||||
s := SleepCT{
|
||||
d: interval,
|
||||
t: time.Now(),
|
||||
}
|
||||
s := sleepct.SleepCT{}
|
||||
s.Start(interval)
|
||||
var i int64
|
||||
for i = 0; i < testCount; i++ {
|
||||
if i+1 < testCount {
|
Loading…
Reference in New Issue
Block a user