package main import ( "io" "log" "net" "os" "path/filepath" "time" "github.com/pkg/sftp" "golang.org/x/crypto/ssh" ) func translateRaspiName(targetName string, cfg RaspiConfig) (string, string, string, string) { for _, n := range cfg.Raspis { if targetName == "" { break } if n.Name == targetName { // Found! return n.Hostname, n.Port, n.Username, n.Password } } return "", "", "", "" } func createSSHClient(targetName string, cfg RaspiConfig) (*ssh.Client, error) { hostname, port, username, password := translateRaspiName(targetName, cfg) log.Println("Connecting to:", hostname, port) config := &ssh.ClientConfig{ User: username, Auth: []ssh.AuthMethod{ ssh.Password(password), }, HostKeyCallback: ssh.InsecureIgnoreHostKey(), // OK for internal tools (and me in production) Timeout: 3 * time.Second, } connAddr := net.JoinHostPort(hostname, port) return ssh.Dial("tcp", connAddr, config) } func runSSHCommand(client *ssh.Client, cmd string) ([]byte, error) { session, err := client.NewSession() if err != nil { return nil, err } defer session.Close() return session.CombinedOutput(cmd) } func verifyCred(targetName string, cfg RaspiConfig) bool { sshClient, err := createSSHClient(targetName, cfg) if err != nil { log.Printf("Err occurred %v", err) return false } defer sshClient.Close() log.Println("Successfully verified the credentials") return true } func sftpUploadFile(targetName, localPath, remotePath string, cfg RaspiConfig) bool { const clearDirectory string = "rm /opt/akartontv/media/*" sshClient, err := createSSHClient(targetName, cfg) fExt := filepath.Ext(localPath) remotePath = remotePath + fExt if err != nil { log.Printf("Failed to init the SSH connection %v", err) return false } defer sshClient.Close() sftpClient, err := sftp.NewClient(sshClient) if err != nil { log.Printf("Failed to start SFTP: %v", err) return false } defer sftpClient.Close() localFile, err := os.Open(localPath) if err != nil { log.Printf("Failed to open local file: %v", err) return false } defer localFile.Close() log.Println("Clearing directory") _, err = runSSHCommand(sshClient, clearDirectory) remoteFile, err := sftpClient.Create(remotePath) if err != nil { log.Printf("Failed to open remote file handle: %v", err) return false } log.Println("Uploading file") bytesCopied, err := io.Copy(remoteFile, localFile) if err != nil { log.Printf("Failed to copy local file to the remote location: %v", err) return false } log.Printf("Succesfully uploaded %d bytes to %s", bytesCopied, remotePath) return true } func restartShow(targetName string, targetMode int, cfg RaspiConfig) bool { const restartPresentation string = "systemctl --user restart presentation" const enablePresentation string = "systemctl --user enable presentation" const disablePresentation string = "systemctl --user disable --now presentation" const restartVideo string = "systemctl --user restart video" const enableVideo string = "systemctl --user enable video" const disableVideo string = "systemctl --user disable --now video" var err error sshClient, err := createSSHClient(targetName, cfg) if err != nil { log.Printf("Failed to init the SSH connection: %v", err) return false } defer sshClient.Close() session, err := sshClient.NewSession() if err != nil { log.Printf("Failed to create session over the connection: %v", err) return false } defer session.Close() switch targetMode { case 1: log.Println("Configuring application workflow: Presentation") _, err = runSSHCommand(sshClient, restartPresentation) _, err = runSSHCommand(sshClient, disableVideo) _, err = runSSHCommand(sshClient, enablePresentation) case 2: log.Println("Configuring application workflow: Video") _, err = runSSHCommand(sshClient, restartVideo) _, err = runSSHCommand(sshClient, disablePresentation) _, err = runSSHCommand(sshClient, enableVideo) } if err != nil { log.Printf("Failed to restart the show over SSH: %v", err) return false } log.Println("Done reloading program!") return true }