diff --git a/go.mod b/go.mod index 14ebb8d..2e7dec4 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/mozillazg/go-pinyin v0.19.0 github.com/rs/zerolog v1.26.1 github.com/urfave/cli/v2 v2.3.0 - go.arsenm.dev/infinitime v0.0.0-20221025193634-0ad671d3f550 + go.arsenm.dev/infinitime v0.0.0-20221107042015-72b558707ee3 go.arsenm.dev/lrpc v0.0.0-20220513001344-3bcc01fdb6a0 golang.org/x/text v0.3.7 modernc.org/sqlite v1.17.2 diff --git a/go.sum b/go.sum index 7e142f1..907a037 100644 --- a/go.sum +++ b/go.sum @@ -397,8 +397,8 @@ github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.4 h1:zNWRjYUW32G9KirMXYHQHVNFkXvMI7LpgNW2AgYAoIs= github.com/yuin/goldmark v1.4.4/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= -go.arsenm.dev/infinitime v0.0.0-20221025193634-0ad671d3f550 h1:GScKSLy9KI83+au3mV9w6koiYRap/uYNarRoUleou4k= -go.arsenm.dev/infinitime v0.0.0-20221025193634-0ad671d3f550/go.mod h1:K3NJ6fyPv5qqHUedB3MccKOE0whJMJZ80l/yTzzTrgc= +go.arsenm.dev/infinitime v0.0.0-20221107042015-72b558707ee3 h1:BfZkb41Gq6h9gy5Cg5jDd5hEk9kI27/h+EX0KN3qZv8= +go.arsenm.dev/infinitime v0.0.0-20221107042015-72b558707ee3/go.mod h1:K3NJ6fyPv5qqHUedB3MccKOE0whJMJZ80l/yTzzTrgc= go.arsenm.dev/lrpc v0.0.0-20220513001344-3bcc01fdb6a0 h1:1K96g1eww+77GeGchwMhd0NTrs7Mk/Hc3M3ItW5NbG4= go.arsenm.dev/lrpc v0.0.0-20220513001344-3bcc01fdb6a0/go.mod h1:goK9z735lfXmqlDxu9qN7FS8t0HJHN3PjyDtCToUY4w= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= diff --git a/main.go b/main.go index dbb567d..c515726 100644 --- a/main.go +++ b/main.go @@ -178,6 +178,12 @@ func main() { log.Error().Err(err).Msg("Error intializing metrics collection") } + // Initialize metrics collection + err = initPureMaps(ctx, dev) + if err != nil { + log.Error().Err(err).Msg("Error intializing puremaps integration") + } + // Start control socket err = startSocket(ctx, dev) if err != nil { diff --git a/maps.go b/maps.go new file mode 100644 index 0000000..dec731f --- /dev/null +++ b/maps.go @@ -0,0 +1,210 @@ +package main + +import ( + "context" + "strings" + + "github.com/godbus/dbus/v5" + "github.com/rs/zerolog/log" + "go.arsenm.dev/infinitime" +) + +const ( + interfaceName = "io.github.rinigus.PureMaps.navigator" + iconProperty = interfaceName + ".icon" + narrativeProperty = interfaceName + ".narrative" + manDistProperty = interfaceName + ".manDist" + progressProperty = interfaceName + ".progress" +) + +func initPureMaps(ctx context.Context, dev *infinitime.Device) error { + // Connect to session bus. This connection is for method calls. + conn, err := newSessionBusConn(ctx) + if err != nil { + return err + } + + exists, err := pureMapsExists(ctx, conn) + if err != nil { + return err + } + + // Connect to session bus. This connection is for method calls. + monitorConn, err := newSessionBusConn(ctx) + if err != nil { + return err + } + + // Define rules to listen for + var rules = []string{ + "type='signal',interface='io.github.rinigus.PureMaps.navigator'", + } + var flag uint = 0 + // Becode monitor for notifications + call := monitorConn.BusObject().CallWithContext( + ctx, "org.freedesktop.DBus.Monitoring.BecomeMonitor", 0, rules, flag, + ) + if call.Err != nil { + return call.Err + } + + var navigator dbus.BusObject + + if exists { + navigator = conn.Object("io.github.rinigus.PureMaps", "/io/github/rinigus/PureMaps/navigator") + err = setAll(navigator, dev) + if err != nil { + log.Error().Err(err).Msg("Error setting all navigation fields") + } + } + + go func() { + signalCh := make(chan *dbus.Message, 10) + monitorConn.Eavesdrop(signalCh) + + for { + select { + case sig := <-signalCh: + if sig.Type != dbus.TypeSignal { + continue + } + + var member string + err = sig.Headers[dbus.FieldMember].Store(&member) + if err != nil { + log.Error().Err(err).Msg("Error getting dbus member field") + continue + } + + if !strings.HasSuffix(member, "Changed") { + continue + } + + log.Debug().Str("member", member).Msg("Signal received from PureMaps navigator") + + // The object must be retrieved in this loop in case PureMaps was not + // open at the time ITD was started. + navigator = conn.Object("io.github.rinigus.PureMaps", "/io/github/rinigus/PureMaps/navigator") + member = strings.TrimSuffix(member, "Changed") + + switch member { + case "icon": + var icon string + err = navigator.StoreProperty(iconProperty, &icon) + if err != nil { + log.Error().Err(err).Str("property", member).Msg("Error getting property") + continue + } + + err = dev.Navigation.SetFlag(infinitime.NavFlag(icon)) + if err != nil { + log.Error().Err(err).Str("property", member).Msg("Error setting flag") + continue + } + case "narrative": + var narrative string + err = navigator.StoreProperty(narrativeProperty, &narrative) + if err != nil { + log.Error().Err(err).Str("property", member).Msg("Error getting property") + continue + } + + err = dev.Navigation.SetNarrative(narrative) + if err != nil { + log.Error().Err(err).Str("property", member).Msg("Error setting flag") + continue + } + case "manDist": + var manDist string + err = navigator.StoreProperty(manDistProperty, &manDist) + if err != nil { + log.Error().Err(err).Str("property", member).Msg("Error getting property") + continue + } + + err = dev.Navigation.SetManDist(manDist) + if err != nil { + log.Error().Err(err).Str("property", member).Msg("Error setting flag") + continue + } + case "progress": + var progress int32 + err = navigator.StoreProperty(progressProperty, &progress) + if err != nil { + log.Error().Err(err).Str("property", member).Msg("Error getting property") + continue + } + + err = dev.Navigation.SetProgress(uint8(progress)) + if err != nil { + log.Error().Err(err).Str("property", member).Msg("Error setting flag") + continue + } + } + case <-ctx.Done(): + return + } + } + }() + + if exists { + log.Info().Msg("Sending PureMaps data to InfiniTime") + } + + return nil +} + +func setAll(navigator dbus.BusObject, dev *infinitime.Device) error { + var icon string + err := navigator.StoreProperty(iconProperty, &icon) + if err != nil { + return err + } + + err = dev.Navigation.SetFlag(infinitime.NavFlag(icon)) + if err != nil { + return err + } + + var narrative string + err = navigator.StoreProperty(narrativeProperty, &narrative) + if err != nil { + return err + } + + err = dev.Navigation.SetNarrative(narrative) + if err != nil { + return err + } + + var manDist string + err = navigator.StoreProperty(manDistProperty, &manDist) + if err != nil { + return err + } + + err = dev.Navigation.SetManDist(manDist) + if err != nil { + return err + } + + var progress int32 + err = navigator.StoreProperty(progressProperty, &progress) + if err != nil { + return err + } + + return dev.Navigation.SetProgress(uint8(progress)) +} + +// pureMapsExists checks to make sure the PureMaps service exists on the bus +func pureMapsExists(ctx context.Context, conn *dbus.Conn) (bool, error) { + var names []string + err := conn.BusObject().CallWithContext( + ctx, "org.freedesktop.DBus.ListNames", 0, + ).Store(&names) + if err != nil { + return false, err + } + return strSlcContains(names, "io.github.rinigus.PureMaps"), nil +}