157 lines
3.1 KiB
Go
157 lines
3.1 KiB
Go
package daemon
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"log"
|
|
"os/exec"
|
|
"sync"
|
|
"syscall"
|
|
"time"
|
|
|
|
"app/telldus"
|
|
)
|
|
|
|
// Manager handles the telldusd daemon lifecycle
|
|
type Manager struct {
|
|
cmd *exec.Cmd
|
|
mu sync.Mutex
|
|
}
|
|
|
|
// New creates a new daemon manager
|
|
func New() *Manager {
|
|
return &Manager{}
|
|
}
|
|
|
|
// Start starts the telldusd daemon and captures its output
|
|
func (m *Manager) Start() error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
if m.cmd != nil && m.cmd.Process != nil {
|
|
log.Println("Telldusd already running")
|
|
return nil
|
|
}
|
|
|
|
log.Println("Starting telldusd...")
|
|
cmd := exec.Command("/usr/local/sbin/telldusd", "--nodaemon")
|
|
|
|
// Capture stdout
|
|
stdout, err := cmd.StdoutPipe()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get stdout pipe: %v", err)
|
|
}
|
|
|
|
// Capture stderr
|
|
stderr, err := cmd.StderrPipe()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get stderr pipe: %v", err)
|
|
}
|
|
|
|
// Start the command
|
|
if err := cmd.Start(); err != nil {
|
|
return fmt.Errorf("failed to start telldusd: %v", err)
|
|
}
|
|
|
|
m.cmd = cmd
|
|
|
|
// Log stdout in a goroutine
|
|
go func() {
|
|
scanner := bufio.NewScanner(stdout)
|
|
for scanner.Scan() {
|
|
log.Printf("[telldusd] %s", scanner.Text())
|
|
}
|
|
}()
|
|
|
|
// Log stderr in a goroutine
|
|
go func() {
|
|
scanner := bufio.NewScanner(stderr)
|
|
for scanner.Scan() {
|
|
log.Printf("[telldusd] ERROR: %s", scanner.Text())
|
|
}
|
|
}()
|
|
|
|
// Monitor process in a goroutine
|
|
go func() {
|
|
err := cmd.Wait()
|
|
m.mu.Lock()
|
|
m.cmd = nil
|
|
m.mu.Unlock()
|
|
if err != nil {
|
|
log.Printf("Telldusd exited with error: %v", err)
|
|
} else {
|
|
log.Println("Telldusd exited normally")
|
|
}
|
|
}()
|
|
|
|
// Give telldusd a moment to start
|
|
time.Sleep(500 * time.Millisecond)
|
|
log.Println("Telldusd started successfully")
|
|
return nil
|
|
}
|
|
|
|
// Stop stops the telldusd daemon
|
|
func (m *Manager) Stop() error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
if m.cmd == nil || m.cmd.Process == nil {
|
|
log.Println("Telldusd not running")
|
|
return nil
|
|
}
|
|
|
|
log.Println("Stopping telldusd...")
|
|
|
|
// Send SIGTERM
|
|
if err := m.cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
|
log.Printf("Failed to send SIGTERM to telldusd: %v", err)
|
|
// Try SIGKILL as fallback
|
|
if err := m.cmd.Process.Kill(); err != nil {
|
|
return fmt.Errorf("failed to kill telldusd: %v", err)
|
|
}
|
|
}
|
|
|
|
// Wait for process to exit (with timeout)
|
|
done := make(chan error, 1)
|
|
go func() {
|
|
done <- m.cmd.Wait()
|
|
}()
|
|
|
|
select {
|
|
case <-done:
|
|
log.Println("Telldusd stopped successfully")
|
|
case <-time.After(5 * time.Second):
|
|
log.Println("Telldusd did not stop gracefully, killing...")
|
|
m.cmd.Process.Kill()
|
|
}
|
|
|
|
m.cmd = nil
|
|
return nil
|
|
}
|
|
|
|
// Restart restarts the telldusd daemon
|
|
func (m *Manager) Restart() error {
|
|
log.Println("Restarting telldusd due to configuration change...")
|
|
|
|
if err := m.Stop(); err != nil {
|
|
log.Printf("Error stopping telldusd: %v", err)
|
|
}
|
|
|
|
// Give it a moment to fully stop
|
|
time.Sleep(1 * time.Second)
|
|
|
|
// Close and reinitialize telldus library
|
|
telldus.Close()
|
|
time.Sleep(500 * time.Millisecond)
|
|
|
|
if err := m.Start(); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Reinitialize telldus library
|
|
telldus.Init()
|
|
|
|
log.Println("Telldusd restarted successfully")
|
|
return nil
|
|
}
|