package main import _ "net/http/pprof" import ( "bufio" "fmt" "io" "log" "net/http" "os" "os/exec" "strings" "syscall" //"gopkg.in/alessio/shellescape.v1" //"github.com/google/shlex" "crypto/tls" "flag" "github.com/alessio/shellescape" "git.2mb.codes/~cmb/barnard/config" "git.2mb.codes/~cmb/barnard/gumble/gumble" _ "git.2mb.codes/~cmb/barnard/gumble/opus" "git.2mb.codes/~cmb/barnard/uiterm" "git.2mb.codes/~cmb/go-openal/openal" ) func show_devs(name string, args []string) { if args == nil { fmt.Printf("no items for %s\n", name) } fmt.Printf("%s\n", name) for i := 0; i < len(args); i++ { fmt.Printf("%s\n", args[i]) } } func do_list_devices() { odevs := openal.GetStrings(openal.AllDevicesSpecifier) if odevs != nil && len(odevs) > 0 { show_devs("All outputs:", odevs) } else { odevs = openal.GetStrings(openal.DeviceSpecifier) show_devs("All outputs:", odevs) } idevs := openal.GetStrings(openal.CaptureDeviceSpecifier) show_devs("Inputs:", idevs) } func setup_notify_runner(notify_command string) chan []string { t := make(chan []string) var do_nothing = false var err error if err != nil { } if notify_command == "" { do_nothing = true } go func(events chan []string, cmd_template string, dummy bool) { for { event := <-events if !dummy { t := string(cmd_template) t = strings.ReplaceAll(t, "%event", shellescape.Quote(event[0])) t = strings.ReplaceAll(t, "%who", shellescape.Quote(event[1])) t = strings.ReplaceAll(t, "%what", shellescape.Quote(event[2])) cmd := "/bin/sh" args := []string{"-c", t} x := exec.Command(cmd, args...) x.Run() } //if we actually have a command to run } //for }(t, notify_command, do_nothing) return t } func setup_fifo(fn string) (chan string, error) { t := make(chan string) if fn == "" { return t, nil } os.Remove(fn) err := syscall.Mkfifo(fn, 0600) if err != nil { return t, err } file, err := os.OpenFile(fn, os.O_RDWR, os.ModeNamedPipe) if err != nil { return t, err } go func(fh io.Reader, out chan string) { reader := bufio.NewReader(fh) for { line, err := reader.ReadBytes('\n') if err == nil { out <- strings.TrimSpace(string(line)) } } }(file, t) return t, nil } func main() { // Command line flags server := flag.String("server", "localhost:64738", "the server to connect to") username := flag.String("username", "", "the username of the client") password := flag.String("password", "", "the password of the server") insecure := flag.Bool("insecure", false, "skip server certificate verification") certificate := flag.String("certificate", "", "PEM encoded certificate and private key") cfgfn := flag.String("config", "~/.barnard.yaml", "Path to YAML formatted configuration file") list_devices := flag.Bool("list_devices", false, "do not connect; instead, list available audio devices and exit") fifo := flag.String("fifo", "", "path of a FIFO from which to read commands") serverSet := false usernameSet := false buffers := flag.Int("buffers", 16, "number of audio buffers to use") profile := flag.Bool("profile", false, "add http server to serve profiles") flag.Parse() if *profile == true { go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }() } userConfig := config.NewConfig(cfgfn) flag.CommandLine.Visit(func(theFlag *flag.Flag) { switch theFlag.Name { case "server": serverSet = true case "username": usernameSet = true } }) if !serverSet { server = userConfig.GetDefaultServer() } if !usernameSet { username = userConfig.GetUsername() } if os.Getenv("ALSOFT_LOGLEVEL") == "" { os.Setenv("ALSOFT_LOGLEVEL", "0") } if *list_devices { do_list_devices() os.Exit(0) } if !strings.Contains(*server, ":") { *server = (*server + ":64738") } // Initialize b := Barnard{ Config: gumble.NewConfig(), UserConfig: userConfig, Address: *server, } b.Config.Buffers = *buffers b.Hotkeys = b.UserConfig.GetHotkeys() b.UserConfig.SaveConfig() b.Config.Username = *username b.Config.Password = *password if *insecure { b.TLSConfig.InsecureSkipVerify = true } if *certificate != "" { cert, err := tls.LoadX509KeyPair(*certificate, *certificate) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } b.TLSConfig.Certificates = append(b.TLSConfig.Certificates, cert) } reader, err := setup_fifo(*fifo) if err != nil { b.exitMessage = err.Error() b.exitStatus = 1 handle_error(b) } b.notifyChannel = setup_notify_runner(*b.UserConfig.GetNotifyCommand()) b.Ui = uiterm.New(&b) b.Ui.Run(reader) handle_error(b) } func handle_raw_error(e error) { fmt.Fprintf(os.Stderr, "%s\n", e.Error()) os.Exit(1) } func handle_error(b Barnard) { if b.exitMessage != "" { fmt.Fprintf(os.Stderr, "%s\n", b.exitMessage) } os.Exit(b.exitStatus) }