yammerbot/main.go

153 lines
3.7 KiB
Go

package main
import (
"flag"
"fmt"
"log"
"os"
"os/signal"
"strconv"
"time"
"github.com/bwmarrin/discordgo"
"github.com/joho/godotenv"
"layeh.com/gumble/gumble"
_ "layeh.com/gumble/opus"
)
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
}
func main() {
godotenv.Load()
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")
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")
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")
}
// Shared Channels
// Shared channels pass PCM information in 10ms chunks [480]int16
var toMumble = make(chan gumble.AudioBuffer, 100)
var toDiscord = make(chan []int16, 100)
// MUMBLE
config := gumble.NewConfig()
config.Username = *mumbleUsername
config.Password = *mumblePassword
config.AudioInterval = time.Millisecond * 10
m := MumbleDuplex{}
mumble, err := gumble.Dial(*mumbleAddr+":"+strconv.Itoa(*mumblePort), config)
if err != nil {
log.Println(err)
return
}
go m.fromMumbleMixer(toDiscord)
go m.sendToMumble(mumble, toMumble)
config.AudioListeners.Attach(m)
log.Println("Mumble Connected")
// DISCORD
discord, err := discordgo.New("Bot " + *discordToken)
if err != nil {
log.Println(err)
return
}
// Open Websocket
err = discord.Open()
if err != nil {
log.Println(err)
return
}
log.Println("Discord Bot Connected")
dgv, err := discord.ChannelVoiceJoin(*discordGID, *discordCID, false, false)
if err != nil {
log.Println(err)
return
}
go discordReceivePCM(dgv, toMumble)
go discordSendPCM(dgv, toDiscord)
// Wait for Exit Signal
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt)
select {
case sig := <-c:
log.Printf("\nGot %s signal. Ending Mumble-Bridge\n", sig)
mumble.Disconnect()
dgv.Speaking(false)
dgv.Close()
discord.Close()
}
}