package app import ( "context" "strings" "time" ) // --------------------------------------------------------------------- // autoloop watcher // --------------------------------------------------------------------- func watchAutoloop(ctx context.Context, every time.Duration) { lastWord := "" lastRaw := "" for { select { case <-ctx.Done(): return case <-time.After(every): } lines := tailFile(autoloopLogPath, 200) word, raw := parseAutoloopStatus(lines) if word == "" && raw == "" { continue } if word == lastWord && raw == lastRaw { continue } lastWord, lastRaw = word, raw events.push("autoloop_status_changed", map[string]string{ "status_word": word, "raw_text": raw, }) } } // --------------------------------------------------------------------- // systemd unit watcher // --------------------------------------------------------------------- func watchSystemdUnit(ctx context.Context, unit string, kind string, every time.Duration) { last := "" for { select { case <-ctx.Done(): return case <-time.After(every): } stdout, _, _, err := runCommand("systemctl", "is-active", unit) state := strings.TrimSpace(stdout) if err != nil || state == "" { state = "unknown" } if state == last { continue } last = state events.push("unit_state_changed", map[string]string{ "unit": unit, "kind": kind, "state": state, }) } } func watchSystemdUnitDynamic(ctx context.Context, resolveUnit func() string, kind string, every time.Duration) { lastUnit := "" lastState := "" for { select { case <-ctx.Done(): return case <-time.After(every): } unit := strings.TrimSpace(resolveUnit()) state := "unknown" if unit != "" { stdout, _, _, err := runCommand("systemctl", "is-active", unit) s := strings.TrimSpace(stdout) if err == nil && s != "" { state = s } } if unit == lastUnit && state == lastState { continue } lastUnit, lastState = unit, state events.push("unit_state_changed", map[string]string{ "unit": unit, "kind": kind, "state": state, }) } }