94 lines
2 KiB
Go
94 lines
2 KiB
Go
package devices
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// TODO: A command device
|
|
// You will be able to use shell commands to push the power button and get the status.
|
|
//
|
|
// Status will give an env variable: WOLBODGE_STATUS_FILE, you will be expected to write a "0" or a "1" there, depending on the state.
|
|
|
|
func NewCommand(shell []string, statusCmd string, toggleStatusCmd string) Device {
|
|
device := &command{
|
|
shell: shell,
|
|
statusCmd: statusCmd,
|
|
toggleStatusCmd: toggleStatusCmd,
|
|
lock: sync.Mutex{},
|
|
}
|
|
return device
|
|
}
|
|
|
|
type command struct {
|
|
shell []string
|
|
statusCmd string
|
|
toggleStatusCmd string
|
|
lock sync.Mutex
|
|
}
|
|
|
|
func (d *command) Status() (bool, error) {
|
|
d.lock.Lock()
|
|
defer d.lock.Unlock()
|
|
|
|
file, err := os.CreateTemp("", "wolbodge-status-*")
|
|
if err != nil {
|
|
return false, fmt.Errorf("failed to create temporary status file: %w", err)
|
|
}
|
|
defer os.Remove(file.Name())
|
|
|
|
cmd := d.makeCommand(d.statusCmd)
|
|
cmd.Env = append(
|
|
cmd.Environ(),
|
|
fmt.Sprintf("WOLBODGE_STATUS_FILE=%s", file.Name()),
|
|
)
|
|
|
|
err = cmd.Run()
|
|
if err != nil {
|
|
return false, fmt.Errorf("failed to run command: %w", err)
|
|
}
|
|
|
|
data, err := os.ReadFile(file.Name())
|
|
if err != nil {
|
|
return false, fmt.Errorf("failed to read status file: %w", err)
|
|
}
|
|
|
|
content := string(data)
|
|
content = strings.TrimSpace(content)
|
|
|
|
switch content {
|
|
case "0":
|
|
return false, nil
|
|
case "1":
|
|
return true, nil
|
|
default:
|
|
return false, fmt.Errorf("invalid status file content, expected \"0\" or \"1\", got \"%s\"", content)
|
|
}
|
|
}
|
|
|
|
func (d *command) ToggleStatus() error {
|
|
d.lock.Lock()
|
|
defer d.lock.Unlock()
|
|
|
|
cmd := d.makeCommand(d.toggleStatusCmd)
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to run command: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (d *command) makeCommand(command string) *exec.Cmd {
|
|
args := make([]string, len(d.shell))
|
|
copy(args, d.shell)
|
|
|
|
for i := range args {
|
|
args[i] = strings.ReplaceAll(args[i], "$COMMAND", command)
|
|
}
|
|
|
|
return exec.Command(args[0], args[1:]...)
|
|
}
|