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:
		
							parent
							
								
									51c7a983a0
								
							
						
					
					
						commit
						ea4f47a1b1
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,2 +1,2 @@
 | 
			
		||||
./main
 | 
			
		||||
./waybar-mpris
 | 
			
		||||
waybar-mpris
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										113
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								main.go
									
									
									
									
									
								
							@ -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)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user