more refinements
This commit is contained in:
189
main.go
189
main.go
@@ -2,13 +2,16 @@ package main
|
||||
|
||||
import (
|
||||
"app/telldus"
|
||||
"bufio"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -17,6 +20,7 @@ import (
|
||||
|
||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -25,6 +29,8 @@ const (
|
||||
|
||||
var mqttDev *mqttDevice
|
||||
var db *sql.DB
|
||||
var telldusCmd *exec.Cmd
|
||||
var telldusMu sync.Mutex
|
||||
|
||||
type mqttDevice struct {
|
||||
client mqtt.Client
|
||||
@@ -216,7 +222,189 @@ var mu sync.Mutex
|
||||
|
||||
const maxEvents = 1000
|
||||
|
||||
// startTelldusd starts the telldusd daemon and captures its output
|
||||
func startTelldusd() error {
|
||||
telldusMu.Lock()
|
||||
defer telldusMu.Unlock()
|
||||
|
||||
if telldusCmd != nil && telldusCmd.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)
|
||||
}
|
||||
|
||||
telldusCmd = 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()
|
||||
telldusMu.Lock()
|
||||
telldusCmd = nil
|
||||
telldusMu.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
|
||||
}
|
||||
|
||||
// stopTelldusd stops the telldusd daemon
|
||||
func stopTelldusd() error {
|
||||
telldusMu.Lock()
|
||||
defer telldusMu.Unlock()
|
||||
|
||||
if telldusCmd == nil || telldusCmd.Process == nil {
|
||||
log.Println("Telldusd not running")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Println("Stopping telldusd...")
|
||||
|
||||
// Send SIGTERM
|
||||
if err := telldusCmd.Process.Signal(syscall.SIGTERM); err != nil {
|
||||
log.Printf("Failed to send SIGTERM to telldusd: %v", err)
|
||||
// Try SIGKILL as fallback
|
||||
if err := telldusCmd.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 <- telldusCmd.Wait()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
log.Println("Telldusd stopped successfully")
|
||||
case <-time.After(5 * time.Second):
|
||||
log.Println("Telldusd did not stop gracefully, killing...")
|
||||
telldusCmd.Process.Kill()
|
||||
}
|
||||
|
||||
telldusCmd = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// restartTelldusd restarts the telldusd daemon
|
||||
func restartTelldusd() error {
|
||||
log.Println("Restarting telldusd due to configuration change...")
|
||||
|
||||
if err := stopTelldusd(); 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 := startTelldusd(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Reinitialize telldus library
|
||||
telldus.Init()
|
||||
|
||||
log.Println("Telldusd restarted successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
// watchConfigFile watches for changes to the tellstick.conf file
|
||||
func watchConfigFile(configPath string) {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Printf("Failed to create file watcher: %v", err)
|
||||
return
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
// Watch the parent directory since file operations might replace the file
|
||||
configDir := filepath.Dir(configPath)
|
||||
if err := watcher.Add(configDir); err != nil {
|
||||
log.Printf("Failed to watch config directory: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Watching for changes to %s", configPath)
|
||||
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// Check if the event is for our config file
|
||||
if event.Name == configPath && (event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create) {
|
||||
log.Printf("Configuration file changed: %s", event.Op.String())
|
||||
if err := restartTelldusd(); err != nil {
|
||||
log.Printf("Failed to restart telldusd: %v", err)
|
||||
}
|
||||
}
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
log.Printf("File watcher error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Start telldusd daemon
|
||||
if err := startTelldusd(); err != nil {
|
||||
log.Fatalf("Failed to start telldusd: %v", err)
|
||||
}
|
||||
defer stopTelldusd()
|
||||
|
||||
// Start watching config file
|
||||
configPath := "/etc/tellstick.conf"
|
||||
go watchConfigFile(configPath)
|
||||
|
||||
// Initialize Telldus
|
||||
telldus.Init()
|
||||
defer telldus.Close()
|
||||
@@ -328,6 +516,7 @@ func main() {
|
||||
log.Println("Shutting down gracefully...")
|
||||
mqttDev.client.Disconnect(250)
|
||||
telldus.Close()
|
||||
stopTelldusd()
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user