only share output when args are identical; use fixed length socket

commands

fixed length commands were originally a guess for an issue I was having,
but it's cleaner this way anyway.
This commit is contained in:
Harvey Tindall 2021-05-17 13:43:56 +01:00
parent 51c7a983a0
commit ea4f47a1b1
Signed by: hrfee
GPG Key ID: BBC65952848FB1A2
2 changed files with 127 additions and 58 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
./main
./waybar-mpris
waybar-mpris

113
main.go
View File

@ -40,6 +40,41 @@ var (
WRITER io.Writer = os.Stdout
)
const (
cPlayerNext = "pn"
cPlayerPrev = "pp"
cNext = "mn"
cPrev = "mp"
cToggle = "mt"
cList = "ls"
cShare = "sh"
cPreShare = "ps"
rSuccess = "sc"
rInvalidCommand = "iv"
)
func stringToCmd(str string) string {
switch str {
case "player-next":
return cPlayerNext
case "player-prev":
return cPlayerPrev
case "next":
return cNext
case "prev":
return cPrev
case "toggle":
return cToggle
case "list":
return cList
case "share":
return cShare
case "pre-share":
return cPreShare
}
return ""
}
// JSON returns json for waybar to consume.
func playerJSON(p *mpris2.Player) string {
symbol := PLAY
@ -140,7 +175,8 @@ func execCommand(cmd string) {
if err != nil {
log.Fatalln("Couldn't dial:", err)
}
_, err = conn.Write([]byte(cmd))
shortCmd := stringToCmd(cmd)
_, err = conn.Write([]byte(shortCmd))
if err != nil {
log.Fatalln("Couldn't send command")
}
@ -158,20 +194,46 @@ func execCommand(cmd string) {
os.Exit(0)
}
func duplicateOutput(conn net.Conn) {
func duplicateOutput() error {
// Print to stderr to avoid errors from waybar
os.Stderr.WriteString("waybar-mpris is already running. This instance will clone its output.")
// Tell other instance to share output in OUTFILE
_, err := conn.Write([]byte("share"))
conn, err := net.Dial("unix", SOCK)
if err != nil {
return err
}
_, err = conn.Write([]byte(cPreShare))
if err != nil {
log.Fatalf("Couldn't send command: %v", err)
return err
}
buf := make([]byte, 512)
nr, err := conn.Read(buf)
if err != nil {
log.Fatalf("Couldn't read response: %v", err)
return err
}
if resp := string(buf[0:nr]); resp == "success" {
argString := ""
for _, arg := range os.Args {
argString += arg + "|"
}
if string(buf[0:nr]) == argString {
conn.Close()
conn, err = net.Dial("unix", SOCK)
if err != nil {
return err
}
// Tell other instance to share output in OUTFILE
_, err := conn.Write([]byte(cShare))
if err != nil {
log.Fatalf("Couldn't send command: %v", err)
}
buf := make([]byte, 2)
nr, err := conn.Read(buf)
if err != nil {
log.Fatalf("Couldn't read response: %v", err)
}
if resp := string(buf[0:nr]); resp == rSuccess {
// t, err := tail.TailFile(OUTFILE, tail.Config{
// Follow: true,
// MustExist: true,
@ -200,13 +262,13 @@ func duplicateOutput(conn net.Conn) {
case event, ok := <-watcher.Events:
if !ok {
log.Printf("Watcher failed: %v", err)
return
return err
}
if event.Op&fsnotify.Write == fsnotify.Write {
l, err := io.ReadAll(f)
if err != nil {
log.Printf("Failed to read file: %v", err)
return
return err
}
str := string(l)
// Trim extra newline is necessary
@ -220,7 +282,8 @@ func duplicateOutput(conn net.Conn) {
}
}
}
}
return nil
}
func listenForCommands(players *players) {
@ -246,7 +309,7 @@ func listenForCommands(players *players) {
log.Println("Couldn't accept:", err)
continue
}
buf := make([]byte, 512)
buf := make([]byte, 2)
nr, err := con.Read(buf)
if err != nil {
log.Println("Couldn't read:", err)
@ -254,7 +317,7 @@ func listenForCommands(players *players) {
}
command := string(buf[0:nr])
switch command {
case "player-next":
case cPlayerNext:
length := len(players.mpris2.List)
if length != 1 {
if players.mpris2.Current < uint(length-1) {
@ -264,7 +327,7 @@ func listenForCommands(players *players) {
}
players.mpris2.Refresh()
}
case "player-prev":
case cPlayerPrev:
length := len(players.mpris2.List)
if length != 1 {
if players.mpris2.Current != 0 {
@ -274,15 +337,15 @@ func listenForCommands(players *players) {
}
players.mpris2.Refresh()
}
case "next":
case cNext:
players.Next()
case "prev":
case cPrev:
players.Prev()
case "toggle":
case cToggle:
players.Toggle()
case "list":
case cList:
con.Write([]byte(players.mpris2.String()))
case "share":
case cShare:
if !isSharing {
f, err := os.OpenFile(OUTFILE, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
defer f.Close()
@ -293,10 +356,20 @@ func listenForCommands(players *players) {
WRITER = io.MultiWriter(os.Stdout, out)
isSharing = true
}
fmt.Fprint(con, "success")
fmt.Fprint(con, rSuccess)
/* Prior to sharing, the first instance sends its os.Args.
If the second instances args are different, the first sends the raw data (artist, album, etc.)
If they are the same, the first instance just sends its output and the second prints it. */
case cPreShare:
out := ""
for _, arg := range os.Args {
out += arg + "|"
}
con.Write([]byte(out))
default:
fmt.Println("Invalid command")
}
con.Close()
}
}
@ -356,13 +429,9 @@ func main() {
ignoreChoice = true
// os.Remove(SOCK)
}
} else if conn, err := net.Dial("unix", SOCK); err == nil {
// When waybar-mpris is already running, we attach to its output instead of launching a whole new instance.
duplicateOutput(conn)
} else {
if err != nil {
} else if err := duplicateOutput(); err != nil {
os.Stdout.WriteString("Couldn't dial socket, deleting instead: " + err.Error())
}
os.Remove(SOCK)
os.Remove(OUTFILE)
}