bound notification delivery and expand placeholders once
Give the notification queue a buffer and drop events when it is full. The channel was unbuffered, so a slow or hung notification command blocked whichever UI or network callback happened to raise the event. Expand the command placeholders in a single pass. Substituting %event, then %who, then %what meant text arriving in an earlier field could contain a later placeholder and have it expanded, letting a remote user inject their own text into the command. Move the command runner behind a build tag and drop the POSIX default on Windows. The helper script it pointed at does not exist there, so the default was a command that could only fail. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
4f41dd4ed6
commit
97ec48534e
@@ -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 ""
|
||||||
|
}
|
||||||
@@ -150,7 +150,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 {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -45,31 +44,28 @@ func do_list_devices() {
|
|||||||
show_devs("Inputs:", idevs)
|
show_devs("Inputs:", idevs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup_notify_runner(notify_command string) chan []string {
|
const notificationQueueSize = 32
|
||||||
t := make(chan []string)
|
|
||||||
var do_nothing = false
|
func setup_notify_runner(notifyCommand string) chan []string {
|
||||||
var err error
|
events := make(chan []string, notificationQueueSize)
|
||||||
if err != nil {
|
go func() {
|
||||||
|
for event := range events {
|
||||||
|
if notifyCommand != "" {
|
||||||
|
runNotification(expandNotification(notifyCommand, event))
|
||||||
}
|
}
|
||||||
if notify_command == "" {
|
|
||||||
do_nothing = true
|
|
||||||
}
|
}
|
||||||
go func(events chan []string, cmd_template string, dummy bool) {
|
}()
|
||||||
for {
|
return events
|
||||||
event := <-events
|
}
|
||||||
if !dummy {
|
|
||||||
t := string(cmd_template)
|
// expandNotification replaces placeholders in one pass so text supplied for
|
||||||
t = strings.ReplaceAll(t, "%event", shellescape.Quote(event[0]))
|
// one field cannot cause another placeholder to be expanded recursively.
|
||||||
t = strings.ReplaceAll(t, "%who", shellescape.Quote(event[1]))
|
func expandNotification(template string, event []string) string {
|
||||||
t = strings.ReplaceAll(t, "%what", shellescape.Quote(event[2]))
|
return strings.NewReplacer(
|
||||||
cmd := "/bin/sh"
|
"%event", shellescape.Quote(event[0]),
|
||||||
args := []string{"-c", t}
|
"%who", shellescape.Quote(event[1]),
|
||||||
x := exec.Command(cmd, args...)
|
"%what", shellescape.Quote(event[2]),
|
||||||
x.Run()
|
).Replace(template)
|
||||||
} //if we actually have a command to run
|
|
||||||
} //for
|
|
||||||
}(t, notify_command, do_nothing)
|
|
||||||
return t
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
@@ -39,7 +39,12 @@ func esc(str string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Barnard) Notify(event string, who string, what string) {
|
func (b *Barnard) Notify(event string, who string, what string) {
|
||||||
b.notifyChannel <- []string{event, who, what}
|
// Notifications are best-effort: a slow external command must not block a
|
||||||
|
// UI or network callback. New events are dropped once the bounded queue is full.
|
||||||
|
select {
|
||||||
|
case b.notifyChannel <- []string{event, who, what}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Barnard) Beep() {
|
func (b *Barnard) Beep() {
|
||||||
|
|||||||
Reference in New Issue
Block a user