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 | ./main | ||||||
| ./waybar-mpris | waybar-mpris | ||||||
|  | |||||||
							
								
								
									
										183
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										183
									
								
								main.go
									
									
									
									
									
								
							| @ -40,6 +40,41 @@ var ( | |||||||
| 	WRITER      io.Writer = os.Stdout | 	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.
 | // JSON returns json for waybar to consume.
 | ||||||
| func playerJSON(p *mpris2.Player) string { | func playerJSON(p *mpris2.Player) string { | ||||||
| 	symbol := PLAY | 	symbol := PLAY | ||||||
| @ -140,7 +175,8 @@ func execCommand(cmd string) { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Fatalln("Couldn't dial:", err) | 		log.Fatalln("Couldn't dial:", err) | ||||||
| 	} | 	} | ||||||
| 	_, err = conn.Write([]byte(cmd)) | 	shortCmd := stringToCmd(cmd) | ||||||
|  | 	_, err = conn.Write([]byte(shortCmd)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Fatalln("Couldn't send command") | 		log.Fatalln("Couldn't send command") | ||||||
| 	} | 	} | ||||||
| @ -158,69 +194,96 @@ func execCommand(cmd string) { | |||||||
| 	os.Exit(0) | 	os.Exit(0) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func duplicateOutput(conn net.Conn) { | func duplicateOutput() error { | ||||||
| 	// Print to stderr to avoid errors from waybar
 | 	// Print to stderr to avoid errors from waybar
 | ||||||
| 	os.Stderr.WriteString("waybar-mpris is already running. This instance will clone its output.") | 	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 { | 	if err != nil { | ||||||
| 		log.Fatalf("Couldn't send command: %v", err) | 		log.Fatalf("Couldn't send command: %v", err) | ||||||
|  | 		return err | ||||||
| 	} | 	} | ||||||
| 	buf := make([]byte, 512) | 	buf := make([]byte, 512) | ||||||
| 	nr, err := conn.Read(buf) | 	nr, err := conn.Read(buf) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Fatalf("Couldn't read response: %v", err) | 		log.Fatalf("Couldn't read response: %v", err) | ||||||
|  | 		return err | ||||||
| 	} | 	} | ||||||
| 	if resp := string(buf[0:nr]); resp == "success" { | 	argString := "" | ||||||
| 		// t, err := tail.TailFile(OUTFILE, tail.Config{
 | 	for _, arg := range os.Args { | ||||||
| 		// 	Follow:    true,
 | 		argString += arg + "|" | ||||||
| 		// 	MustExist: true,
 | 	} | ||||||
| 		// 	Logger:    tail.DiscardingLogger,
 | 	if string(buf[0:nr]) == argString { | ||||||
| 		// })
 | 		conn.Close() | ||||||
| 		// if err == nil {
 | 		conn, err = net.Dial("unix", SOCK) | ||||||
| 		// 	for line := range t.Lines {
 |  | ||||||
| 		// 		fmt.Println(line.Text)
 |  | ||||||
| 		// 	}
 |  | ||||||
| 		// }
 |  | ||||||
| 		f, err := os.Open(OUTFILE) |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.Fatalf("Failed to open \"%s\": %v", OUTFILE, err) | 			return err | ||||||
| 		} | 		} | ||||||
| 		watcher, err := fsnotify.NewWatcher() | 		// Tell other instance to share output in OUTFILE
 | ||||||
|  | 		_, err := conn.Write([]byte(cShare)) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.Fatalf("Failed to start watcher: %v", err) | 			log.Fatalf("Couldn't send command: %v", err) | ||||||
| 		} | 		} | ||||||
| 		defer watcher.Close() | 		buf := make([]byte, 2) | ||||||
| 		err = watcher.Add(OUTFILE) | 		nr, err := conn.Read(buf) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.Fatalf("Failed to watch file: %v", err) | 			log.Fatalf("Couldn't read response: %v", err) | ||||||
| 		} | 		} | ||||||
| 		for { | 		if resp := string(buf[0:nr]); resp == rSuccess { | ||||||
| 			select { | 			// t, err := tail.TailFile(OUTFILE, tail.Config{
 | ||||||
| 			case event, ok := <-watcher.Events: | 			// 	Follow:    true,
 | ||||||
| 				if !ok { | 			// 	MustExist: true,
 | ||||||
| 					log.Printf("Watcher failed: %v", err) | 			// 	Logger:    tail.DiscardingLogger,
 | ||||||
| 					return | 			// })
 | ||||||
| 				} | 			// if err == nil {
 | ||||||
| 				if event.Op&fsnotify.Write == fsnotify.Write { | 			// 	for line := range t.Lines {
 | ||||||
| 					l, err := io.ReadAll(f) | 			// 		fmt.Println(line.Text)
 | ||||||
| 					if err != nil { | 			// 	}
 | ||||||
| 						log.Printf("Failed to read file: %v", err) | 			// }
 | ||||||
| 						return | 			f, err := os.Open(OUTFILE) | ||||||
|  | 			if err != nil { | ||||||
|  | 				log.Fatalf("Failed to open \"%s\": %v", OUTFILE, err) | ||||||
|  | 			} | ||||||
|  | 			watcher, err := fsnotify.NewWatcher() | ||||||
|  | 			if err != nil { | ||||||
|  | 				log.Fatalf("Failed to start watcher: %v", err) | ||||||
|  | 			} | ||||||
|  | 			defer watcher.Close() | ||||||
|  | 			err = watcher.Add(OUTFILE) | ||||||
|  | 			if err != nil { | ||||||
|  | 				log.Fatalf("Failed to watch file: %v", err) | ||||||
|  | 			} | ||||||
|  | 			for { | ||||||
|  | 				select { | ||||||
|  | 				case event, ok := <-watcher.Events: | ||||||
|  | 					if !ok { | ||||||
|  | 						log.Printf("Watcher failed: %v", err) | ||||||
|  | 						return err | ||||||
| 					} | 					} | ||||||
| 					str := string(l) | 					if event.Op&fsnotify.Write == fsnotify.Write { | ||||||
| 					// Trim extra newline is necessary
 | 						l, err := io.ReadAll(f) | ||||||
| 					if str[len(str)-2:] == "\n\n" { | 						if err != nil { | ||||||
| 						fmt.Print(str[:len(str)-1]) | 							log.Printf("Failed to read file: %v", err) | ||||||
| 					} else { | 							return err | ||||||
| 						fmt.Print(str) | 						} | ||||||
|  | 						str := string(l) | ||||||
|  | 						// Trim extra newline is necessary
 | ||||||
|  | 						if str[len(str)-2:] == "\n\n" { | ||||||
|  | 							fmt.Print(str[:len(str)-1]) | ||||||
|  | 						} else { | ||||||
|  | 							fmt.Print(str) | ||||||
|  | 						} | ||||||
|  | 						f.Seek(0, 0) | ||||||
| 					} | 					} | ||||||
| 					f.Seek(0, 0) |  | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func listenForCommands(players *players) { | func listenForCommands(players *players) { | ||||||
| @ -246,7 +309,7 @@ func listenForCommands(players *players) { | |||||||
| 			log.Println("Couldn't accept:", err) | 			log.Println("Couldn't accept:", err) | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		buf := make([]byte, 512) | 		buf := make([]byte, 2) | ||||||
| 		nr, err := con.Read(buf) | 		nr, err := con.Read(buf) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.Println("Couldn't read:", err) | 			log.Println("Couldn't read:", err) | ||||||
| @ -254,7 +317,7 @@ func listenForCommands(players *players) { | |||||||
| 		} | 		} | ||||||
| 		command := string(buf[0:nr]) | 		command := string(buf[0:nr]) | ||||||
| 		switch command { | 		switch command { | ||||||
| 		case "player-next": | 		case cPlayerNext: | ||||||
| 			length := len(players.mpris2.List) | 			length := len(players.mpris2.List) | ||||||
| 			if length != 1 { | 			if length != 1 { | ||||||
| 				if players.mpris2.Current < uint(length-1) { | 				if players.mpris2.Current < uint(length-1) { | ||||||
| @ -264,7 +327,7 @@ func listenForCommands(players *players) { | |||||||
| 				} | 				} | ||||||
| 				players.mpris2.Refresh() | 				players.mpris2.Refresh() | ||||||
| 			} | 			} | ||||||
| 		case "player-prev": | 		case cPlayerPrev: | ||||||
| 			length := len(players.mpris2.List) | 			length := len(players.mpris2.List) | ||||||
| 			if length != 1 { | 			if length != 1 { | ||||||
| 				if players.mpris2.Current != 0 { | 				if players.mpris2.Current != 0 { | ||||||
| @ -274,15 +337,15 @@ func listenForCommands(players *players) { | |||||||
| 				} | 				} | ||||||
| 				players.mpris2.Refresh() | 				players.mpris2.Refresh() | ||||||
| 			} | 			} | ||||||
| 		case "next": | 		case cNext: | ||||||
| 			players.Next() | 			players.Next() | ||||||
| 		case "prev": | 		case cPrev: | ||||||
| 			players.Prev() | 			players.Prev() | ||||||
| 		case "toggle": | 		case cToggle: | ||||||
| 			players.Toggle() | 			players.Toggle() | ||||||
| 		case "list": | 		case cList: | ||||||
| 			con.Write([]byte(players.mpris2.String())) | 			con.Write([]byte(players.mpris2.String())) | ||||||
| 		case "share": | 		case cShare: | ||||||
| 			if !isSharing { | 			if !isSharing { | ||||||
| 				f, err := os.OpenFile(OUTFILE, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666) | 				f, err := os.OpenFile(OUTFILE, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666) | ||||||
| 				defer f.Close() | 				defer f.Close() | ||||||
| @ -293,10 +356,20 @@ func listenForCommands(players *players) { | |||||||
| 				WRITER = io.MultiWriter(os.Stdout, out) | 				WRITER = io.MultiWriter(os.Stdout, out) | ||||||
| 				isSharing = true | 				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: | 		default: | ||||||
| 			fmt.Println("Invalid command") | 			fmt.Println("Invalid command") | ||||||
| 		} | 		} | ||||||
|  | 		con.Close() | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -356,13 +429,9 @@ func main() { | |||||||
| 				ignoreChoice = true | 				ignoreChoice = true | ||||||
| 				// os.Remove(SOCK)
 | 				// 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.
 | 			// When waybar-mpris is already running, we attach to its output instead of launching a whole new instance.
 | ||||||
| 			duplicateOutput(conn) | 		} else if err := duplicateOutput(); err != nil { | ||||||
| 		} else { | 			os.Stdout.WriteString("Couldn't dial socket, deleting instead: " + err.Error()) | ||||||
| 			if err != nil { |  | ||||||
| 				os.Stdout.WriteString("Couldn't dial socket, deleting instead: " + err.Error()) |  | ||||||
| 			} |  | ||||||
| 			os.Remove(SOCK) | 			os.Remove(SOCK) | ||||||
| 			os.Remove(OUTFILE) | 			os.Remove(OUTFILE) | ||||||
| 		} | 		} | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user