package main import ( "context" "errors" "log/slog" "net/http" "os" "os/signal" "git.t-juice.club/torjus/ghettoptt/bus" "git.t-juice.club/torjus/ghettoptt/debouncer" "git.t-juice.club/torjus/ghettoptt/metrics" "github.com/holoplot/go-evdev" "github.com/prometheus/client_golang/prometheus/promhttp" ) const Version = "v0.1.3" func main() { // Setup logger h := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}) logger := slog.New(h) slog.SetDefault(logger) // Setup signal handler ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) defer stop() // Setup metrics m := metrics.NewMumbleMetricsCollector() mbus := bus.NewMumbleBus(m) defer mbus.Close() // Start reading input events input, err := evdev.OpenWithFlags("/dev/input/by-id/usb-SteelSeries_SteelSeries_Rival_710_Gaming_Mouse-if02-event-kbd", os.O_RDONLY) if err != nil { panic(err) } defer input.Close() input.NonBlock() var done bool // Start metrics server srvCtx, srvCancel := context.WithCancel(context.Background()) defer srvCancel() go func() { mux := http.NewServeMux() mux.Handle("/metrics", promhttp.Handler()) srv := http.Server{ Handler: mux, Addr: ":8989", } go func() { <-ctx.Done() srv.Shutdown(context.Background()) srvCancel() }() slog.Info("Starting metrics server", "addr", srv.Addr) srv.ListenAndServe() }() // Listen for context cancellation go func() { <-ctx.Done() done = true input.Close() }() // Start listening for PTT key slog.Info("Starting event listener", "version", Version) eventCh := make(chan bool) doneCtx, doneCancel := context.WithCancel(srvCtx) defer doneCancel() debouncer := debouncer.New(eventCh) go func() { var done bool for !done { ev, err := input.ReadOne() if err != nil { if errors.Is(err, os.ErrClosed) { continue } slog.Error("Error reading from input device", "error", err) mbus.StopTalking() os.Exit(1) } if ev.Code == evdev.KEY_F24 && ev.Value == 1 { slog.Debug("PTT ON") eventCh <- true } if ev.Code == evdev.KEY_F24 && ev.Value == 0 { slog.Debug("PTT OFF") eventCh <- false } if doneCtx.Err() != nil { close(eventCh) done = true } } }() for v := range debouncer.C { if v { mbus.StartTalking() slog.Info("Started talking") } else { mbus.StopTalking() slog.Info("Stopped talking") } } mbus.StopTalking() <-srvCtx.Done() slog.Info("Exiting") }