2026-01-08 15:45:00 +01:00
|
|
|
package main
|
|
|
|
|
|
2026-01-08 17:30:28 +01:00
|
|
|
import (
|
2026-01-12 16:28:52 +01:00
|
|
|
"io"
|
2026-01-08 17:30:28 +01:00
|
|
|
"log"
|
|
|
|
|
"net"
|
2026-01-12 16:28:52 +01:00
|
|
|
"os"
|
2026-01-13 15:46:03 +01:00
|
|
|
"path/filepath"
|
2026-01-08 17:30:28 +01:00
|
|
|
"time"
|
2026-01-08 15:45:00 +01:00
|
|
|
|
2026-01-12 16:28:52 +01:00
|
|
|
"github.com/pkg/sftp"
|
2026-01-08 17:30:28 +01:00
|
|
|
"golang.org/x/crypto/ssh"
|
|
|
|
|
)
|
|
|
|
|
|
2026-01-12 16:58:20 +01:00
|
|
|
func translateRaspiName(targetName string, cfg RaspiConfig) (string, string, string, string) {
|
|
|
|
|
for _, n := range cfg.Raspis {
|
2026-01-12 16:28:52 +01:00
|
|
|
if targetName == "" {
|
|
|
|
|
break
|
|
|
|
|
}
|
2026-01-12 16:58:20 +01:00
|
|
|
if n.Name == targetName {
|
2026-01-08 17:30:28 +01:00
|
|
|
// Found!
|
2026-01-12 16:58:20 +01:00
|
|
|
return n.Hostname, n.Port, n.Username, n.Password
|
2026-01-08 17:30:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-09 17:01:49 +01:00
|
|
|
return "", "", "", ""
|
2026-01-08 17:30:28 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-12 16:58:20 +01:00
|
|
|
func createSSHClient(targetName string, cfg RaspiConfig) (*ssh.Client, error) {
|
|
|
|
|
hostname, port, username, password := translateRaspiName(targetName, cfg)
|
2026-01-08 17:30:28 +01:00
|
|
|
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)
|
2026-01-12 16:28:52 +01:00
|
|
|
Timeout: 3 * time.Second,
|
2026-01-08 17:30:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
connAddr := net.JoinHostPort(hostname, port)
|
2026-01-12 16:28:52 +01:00
|
|
|
return ssh.Dial("tcp", connAddr, config)
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 15:46:03 +01:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-12 16:58:20 +01:00
|
|
|
func verifyCred(targetName string, cfg RaspiConfig) bool {
|
|
|
|
|
sshClient, err := createSSHClient(targetName, cfg)
|
2026-01-08 17:30:28 +01:00
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("Err occurred %v", err)
|
|
|
|
|
return false
|
|
|
|
|
}
|
2026-01-12 16:28:52 +01:00
|
|
|
defer sshClient.Close()
|
2026-01-08 17:30:28 +01:00
|
|
|
|
2026-01-13 15:46:03 +01:00
|
|
|
log.Println("Successfully verified the credentials")
|
2026-01-08 17:30:28 +01:00
|
|
|
return true
|
2026-01-08 15:45:00 +01:00
|
|
|
}
|
2026-01-12 16:28:52 +01:00
|
|
|
|
2026-01-12 16:58:20 +01:00
|
|
|
func sftpUploadFile(targetName, localPath, remotePath string, cfg RaspiConfig) bool {
|
2026-01-15 16:48:03 +01:00
|
|
|
const clearDirectory string = "rm /opt/raspscreen/media/*"
|
2026-01-13 15:46:03 +01:00
|
|
|
|
2026-01-12 16:58:20 +01:00
|
|
|
sshClient, err := createSSHClient(targetName, cfg)
|
2026-01-12 16:28:52 +01:00
|
|
|
|
2026-01-13 15:46:03 +01:00
|
|
|
fExt := filepath.Ext(localPath)
|
|
|
|
|
remotePath = remotePath + fExt
|
|
|
|
|
|
2026-01-12 16:28:52 +01:00
|
|
|
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()
|
|
|
|
|
|
2026-01-13 15:46:03 +01:00
|
|
|
log.Println("Clearing directory")
|
|
|
|
|
_, err = runSSHCommand(sshClient, clearDirectory)
|
|
|
|
|
|
2026-01-12 16:28:52 +01:00
|
|
|
remoteFile, err := sftpClient.Create(remotePath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("Failed to open remote file handle: %v", err)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 15:46:03 +01:00
|
|
|
log.Println("Uploading file")
|
2026-01-12 16:28:52 +01:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 10:49:20 +01:00
|
|
|
func restartShow(targetName string, targetMode int, cfg RaspiConfig) bool {
|
2026-02-06 11:34:24 +01:00
|
|
|
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
|
2026-01-13 10:49:20 +01:00
|
|
|
|
2026-01-13 15:46:03 +01:00
|
|
|
var err error
|
2026-01-12 16:58:20 +01:00
|
|
|
sshClient, err := createSSHClient(targetName, cfg)
|
2026-01-12 16:28:52 +01:00
|
|
|
|
|
|
|
|
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)
|
2026-01-13 10:49:20 +01:00
|
|
|
return false
|
2026-01-12 16:28:52 +01:00
|
|
|
}
|
|
|
|
|
defer session.Close()
|
|
|
|
|
|
2026-02-06 11:34:24 +01:00
|
|
|
var servName string
|
2026-01-13 10:49:20 +01:00
|
|
|
switch targetMode {
|
|
|
|
|
case 1:
|
2026-02-06 11:34:24 +01:00
|
|
|
servName = "presentation"
|
2026-01-13 10:49:20 +01:00
|
|
|
case 2:
|
2026-02-06 11:34:24 +01:00
|
|
|
servName = "video"
|
2026-01-13 10:49:20 +01:00
|
|
|
}
|
2026-02-06 11:34:24 +01:00
|
|
|
log.Println("Configuring application workflow:", servName)
|
|
|
|
|
|
|
|
|
|
stitchCmd := switchCmd + servName
|
|
|
|
|
_, err = runSSHCommand(sshClient, stitchCmd)
|
2026-01-13 10:49:20 +01:00
|
|
|
|
2026-01-12 16:28:52 +01:00
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("Failed to restart the show over SSH: %v", err)
|
2026-01-13 10:49:20 +01:00
|
|
|
return false
|
2026-01-12 16:28:52 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-13 15:46:03 +01:00
|
|
|
log.Println("Done reloading program!")
|
2026-01-12 16:28:52 +01:00
|
|
|
return true
|
|
|
|
|
}
|