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/raspscreen/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 switchCmd string = "/opt/raspscreen/bin/manage.sh switch-state " // add a blank/whitespace at the end to make the formatting valid for manage.sh 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() var servName string switch targetMode { case 1: servName = "presentation" case 2: servName = "video" } log.Println("Configuring application workflow:", servName) stitchCmd := switchCmd + servName _, err = runSSHCommand(sshClient, stitchCmd) if err != nil { log.Printf("Failed to restart the show over SSH: %v", err) return false } log.Println("Done reloading program!") return true }