Add Windows platform integration scaffolding
This commit is contained in:
committed by
Brandon McGinty
parent
fab4fd50d2
commit
9c487c2586
+22
@@ -0,0 +1,22 @@
|
|||||||
|
# Windows support
|
||||||
|
|
||||||
|
Barnard can be built for Windows with a native CGO toolchain. Audio support uses native OpenAL Soft, libopus, libopusfile/libogg, and RNNoise; `ffmpeg.exe` must also be on `PATH` for recording and file playback.
|
||||||
|
|
||||||
|
The easiest supported setup is MSYS2 MinGW-w64. Install the matching architecture's Go toolchain and development packages for OpenAL Soft, opus, opusfile, libogg, RNNoise, FFmpeg, and pkg-config. Build from its MinGW shell:
|
||||||
|
|
||||||
|
```
|
||||||
|
go build -o barnard.exe .
|
||||||
|
```
|
||||||
|
|
||||||
|
For cross-compilation from Linux, use the matching MinGW compiler and its pkg-config environment, for example:
|
||||||
|
|
||||||
|
```
|
||||||
|
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 \
|
||||||
|
CC=x86_64-w64-mingw32-gcc \
|
||||||
|
PKG_CONFIG=x86_64-w64-mingw32-pkg-config \
|
||||||
|
go build -o barnard.exe .
|
||||||
|
```
|
||||||
|
|
||||||
|
The dependency include and library paths must point to Windows builds, not host Linux libraries.
|
||||||
|
|
||||||
|
The legacy `--fifo` command control is unavailable on Windows because it uses POSIX filesystem FIFOs. Windows defaults to no notification command; an explicitly configured notification command is run by `cmd.exe /C`.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
func defaultNotifyCommand() string {
|
||||||
|
return "/usr/share/barnard/barnard-sound.sh \"%event\" \"%who\" \"%what\""
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
// Windows installations do not ship the POSIX notification helper. Users can
|
||||||
|
// configure a cmd.exe-compatible command explicitly if they want notifications.
|
||||||
|
func defaultNotifyCommand() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@@ -148,7 +148,7 @@ func (c *Config) LoadConfig() {
|
|||||||
jc.Username = &username
|
jc.Username = &username
|
||||||
}
|
}
|
||||||
if c.config.NotifyCommand == nil {
|
if c.config.NotifyCommand == nil {
|
||||||
ncmd := string("/usr/share/barnard/barnard-sound.sh \"%event\" \"%who\" \"%what\"")
|
ncmd := defaultNotifyCommand()
|
||||||
jc.NotifyCommand = &ncmd
|
jc.NotifyCommand = &ncmd
|
||||||
}
|
}
|
||||||
if c.config.NoiseSuppressionEnabled == nil {
|
if c.config.NoiseSuppressionEnabled == nil {
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setup_fifo(fn string) (chan string, error) {
|
||||||
|
commands := make(chan string)
|
||||||
|
if fn == "" {
|
||||||
|
return commands, nil
|
||||||
|
}
|
||||||
|
if info, err := os.Lstat(fn); err == nil {
|
||||||
|
if info.Mode()&os.ModeNamedPipe == 0 {
|
||||||
|
return commands, fmt.Errorf("FIFO path %q already exists and is not a FIFO", fn)
|
||||||
|
}
|
||||||
|
if err := os.Remove(fn); err != nil {
|
||||||
|
return commands, err
|
||||||
|
}
|
||||||
|
} else if !os.IsNotExist(err) {
|
||||||
|
return commands, err
|
||||||
|
}
|
||||||
|
if err := syscall.Mkfifo(fn, 0600); err != nil {
|
||||||
|
return commands, err
|
||||||
|
}
|
||||||
|
file, err := os.OpenFile(fn, os.O_RDWR, os.ModeNamedPipe)
|
||||||
|
if err != nil {
|
||||||
|
return commands, err
|
||||||
|
}
|
||||||
|
go readFIFO(file, commands)
|
||||||
|
return commands, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readFIFO forwards complete commands and terminates on EOF or any read
|
||||||
|
// failure. Retrying an unrecoverable FIFO error used to spin a CPU forever.
|
||||||
|
func readFIFO(fh io.ReadCloser, out chan<- string) {
|
||||||
|
defer fh.Close()
|
||||||
|
defer close(out)
|
||||||
|
reader := bufio.NewReader(fh)
|
||||||
|
for {
|
||||||
|
line, err := reader.ReadBytes('\n')
|
||||||
|
if len(line) != 0 {
|
||||||
|
out <- strings.TrimSpace(string(line))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Windows named pipes require the Win32 API rather than POSIX filesystem
|
||||||
|
// FIFOs. Disable the legacy FIFO option until it is replaced with a named-pipe
|
||||||
|
// listener; ordinary UI and command-line operation remain available.
|
||||||
|
func setup_fifo(fn string) (chan string, error) {
|
||||||
|
commands := make(chan string)
|
||||||
|
if strings.TrimSpace(fn) == "" {
|
||||||
|
return commands, nil
|
||||||
|
}
|
||||||
|
return commands, fmt.Errorf("FIFO control is not supported on Windows")
|
||||||
|
}
|
||||||
@@ -3,18 +3,14 @@ package main
|
|||||||
import _ "net/http/pprof"
|
import _ "net/http/pprof"
|
||||||
import (
|
import (
|
||||||
"al.essio.dev/pkg/shellescape"
|
"al.essio.dev/pkg/shellescape"
|
||||||
"bufio"
|
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
barnlog "git.stormux.org/storm/barnard/log"
|
barnlog "git.stormux.org/storm/barnard/log"
|
||||||
|
|
||||||
@@ -50,26 +46,16 @@ func do_list_devices() {
|
|||||||
|
|
||||||
const notificationQueueSize = 32
|
const notificationQueueSize = 32
|
||||||
|
|
||||||
func setup_notify_runner(notify_command string) chan []string {
|
func setup_notify_runner(notifyCommand string) chan []string {
|
||||||
t := make(chan []string, notificationQueueSize)
|
events := make(chan []string, notificationQueueSize)
|
||||||
var do_nothing = false
|
go func() {
|
||||||
var err error
|
|
||||||
if err != nil {
|
|
||||||
}
|
|
||||||
if notify_command == "" {
|
|
||||||
do_nothing = true
|
|
||||||
}
|
|
||||||
go func(events chan []string, cmd_template string, dummy bool) {
|
|
||||||
for event := range events {
|
for event := range events {
|
||||||
if !dummy {
|
if notifyCommand != "" {
|
||||||
cmd := "/bin/sh"
|
runNotification(expandNotification(notifyCommand, event))
|
||||||
args := []string{"-c", expandNotification(cmd_template, event)}
|
|
||||||
x := exec.Command(cmd, args...)
|
|
||||||
x.Run()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(t, notify_command, do_nothing)
|
}()
|
||||||
return t
|
return events
|
||||||
}
|
}
|
||||||
|
|
||||||
// expandNotification replaces placeholders in one pass so text supplied for
|
// expandNotification replaces placeholders in one pass so text supplied for
|
||||||
@@ -82,50 +68,6 @@ func expandNotification(template string, event []string) string {
|
|||||||
).Replace(template)
|
).Replace(template)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup_fifo(fn string) (chan string, error) {
|
|
||||||
t := make(chan string)
|
|
||||||
if fn == "" {
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
if info, err := os.Lstat(fn); err == nil {
|
|
||||||
if info.Mode()&os.ModeNamedPipe == 0 {
|
|
||||||
return t, fmt.Errorf("FIFO path %q already exists and is not a FIFO", fn)
|
|
||||||
}
|
|
||||||
if err := os.Remove(fn); err != nil {
|
|
||||||
return t, err
|
|
||||||
}
|
|
||||||
} else if !os.IsNotExist(err) {
|
|
||||||
return t, err
|
|
||||||
}
|
|
||||||
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 readFIFO(file, t)
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// readFIFO forwards complete commands and terminates on EOF or any read
|
|
||||||
// failure. Retrying an unrecoverable FIFO error used to spin a CPU forever.
|
|
||||||
func readFIFO(fh io.ReadCloser, out chan<- string) {
|
|
||||||
defer fh.Close()
|
|
||||||
defer close(out)
|
|
||||||
reader := bufio.NewReader(fh)
|
|
||||||
for {
|
|
||||||
line, err := reader.ReadBytes('\n')
|
|
||||||
if len(line) != 0 {
|
|
||||||
out <- strings.TrimSpace(string(line))
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Command line flags
|
// Command line flags
|
||||||
server := flag.String("server", "localhost:64738", "the server to connect to")
|
server := flag.String("server", "localhost:64738", "the server to connect to")
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "os/exec"
|
||||||
|
|
||||||
|
func runNotification(command string) {
|
||||||
|
_ = exec.Command("/bin/sh", "-c", command).Run()
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "os/exec"
|
||||||
|
|
||||||
|
func runNotification(command string) {
|
||||||
|
_ = exec.Command("cmd.exe", "/C", command).Run()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user