mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
68 lines
2.0 KiB
Go
68 lines
2.0 KiB
Go
package roverd
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
const roverConsolePath = "/dev/tty1"
|
|
|
|
// ConsoleNotifier writes the small set of rover lifecycle events that must be
|
|
// visible even when nobody is logged in. This intentionally targets tty1
|
|
// directly instead of using wall: wall discovers recipients through utmp, so
|
|
// it does not reliably reach a virtual console that is only showing a login
|
|
// prompt.
|
|
type ConsoleNotifier struct {
|
|
path string
|
|
logger *log.Logger
|
|
mu sync.Mutex
|
|
}
|
|
|
|
// NewConsoleNotifier returns the production notifier for the rover's primary
|
|
// local virtual console. Keeping the path inside the notifier also gives tests
|
|
// a way to substitute a regular temporary file without touching a real TTY.
|
|
func NewConsoleNotifier(logger *log.Logger) *ConsoleNotifier {
|
|
return newConsoleNotifier(roverConsolePath, logger)
|
|
}
|
|
|
|
func newConsoleNotifier(path string, logger *log.Logger) *ConsoleNotifier {
|
|
return &ConsoleNotifier{path: path, logger: logger}
|
|
}
|
|
|
|
// Notify appends one self-contained alert to the console. Console output is a
|
|
// diagnostic convenience rather than part of rover control, so an unavailable
|
|
// tty is logged but never allowed to stop startup, reconnection, docking, or
|
|
// reboot behavior.
|
|
func (n *ConsoleNotifier) Notify(message string) {
|
|
if n == nil {
|
|
return
|
|
}
|
|
|
|
n.mu.Lock()
|
|
defer n.mu.Unlock()
|
|
|
|
console, err := os.OpenFile(n.path, os.O_WRONLY|os.O_APPEND, 0)
|
|
if err != nil {
|
|
n.logFailure("open", err)
|
|
return
|
|
}
|
|
defer console.Close()
|
|
|
|
// Leading and trailing CRLFs keep the alert separate from an agetty login
|
|
// prompt, while plain text avoids leaving an unknown terminal in a modified
|
|
// color or cursor state.
|
|
timestamp := time.Now().UTC().Format("2006-01-02 15:04:05 UTC")
|
|
if _, err := fmt.Fprintf(console, "\r\n*** rover alert - %s ***\r\n%s\r\n", timestamp, message); err != nil {
|
|
n.logFailure("write", err)
|
|
}
|
|
}
|
|
|
|
func (n *ConsoleNotifier) logFailure(operation string, err error) {
|
|
if n.logger != nil {
|
|
n.logger.Printf("console notification %s failed for %s: %v", operation, n.path, err)
|
|
}
|
|
}
|