From 60f1eedc9ad43f14c12e100bd923670f59463e2e Mon Sep 17 00:00:00 2001 From: Arsen Musayelyan Date: Wed, 11 May 2022 13:24:12 -0700 Subject: [PATCH] Create and propagate contexts wherever possible --- calls.go | 31 +++++++++++++++++++------------ dbus.go | 14 +++++++++----- go.mod | 2 +- go.sum | 4 ++-- main.go | 29 ++++++++++++++++++++++++----- metrics.go | 11 ++++++----- notifs.go | 9 ++++++--- socket.go | 52 ++++++++++++---------------------------------------- weather.go | 20 +++++++++++++------- 9 files changed, 92 insertions(+), 80 deletions(-) diff --git a/calls.go b/calls.go index b1e1227..04ded15 100644 --- a/calls.go +++ b/calls.go @@ -1,6 +1,7 @@ package main import ( + "context" "sync" "github.com/godbus/dbus/v5" @@ -8,15 +9,15 @@ import ( "go.arsenm.dev/infinitime" ) -func initCallNotifs(dev *infinitime.Device) error { +func initCallNotifs(ctx context.Context, dev *infinitime.Device) error { // Connect to system bus. This connection is for method calls. - conn, err := newSystemBusConn() + conn, err := newSystemBusConn(ctx) if err != nil { return err } // Check if modem manager interface exists - exists, err := modemManagerExists(conn) + exists, err := modemManagerExists(ctx, conn) if err != nil { return err } @@ -28,7 +29,7 @@ func initCallNotifs(dev *infinitime.Device) error { } // Connect to system bus. This connection is for monitoring. - monitorConn, err := newSystemBusConn() + monitorConn, err := newSystemBusConn(ctx) if err != nil { return err } @@ -78,13 +79,13 @@ func initCallNotifs(dev *infinitime.Device) error { switch res { case infinitime.CallStatusAccepted: // Attempt to accept call - err = acceptCall(conn, callObj) + err = acceptCall(ctx, conn, callObj) if err != nil { log.Warn().Err(err).Msg("Error accepting call") } case infinitime.CallStatusDeclined: // Attempt to decline call - err = declineCall(conn, callObj) + err = declineCall(ctx, conn, callObj) if err != nil { log.Warn().Err(err).Msg("Error declining call") } @@ -101,9 +102,11 @@ func initCallNotifs(dev *infinitime.Device) error { return nil } -func modemManagerExists(conn *dbus.Conn) (bool, error) { +func modemManagerExists(ctx context.Context, conn *dbus.Conn) (bool, error) { var names []string - err := conn.BusObject().Call("org.freedesktop.DBus.ListNames", 0).Store(&names) + err := conn.BusObject().CallWithContext( + ctx, "org.freedesktop.DBus.ListNames", 0, + ).Store(&names) if err != nil { return false, err } @@ -122,9 +125,11 @@ func getPhoneNum(conn *dbus.Conn, callObj dbus.BusObject) (string, error) { } // getPhoneNum accepts a call using a DBus connection -func acceptCall(conn *dbus.Conn, callObj dbus.BusObject) error { +func acceptCall(ctx context.Context, conn *dbus.Conn, callObj dbus.BusObject) error { // Call Accept() method on DBus object - call := callObj.Call("org.freedesktop.ModemManager1.Call.Accept", 0) + call := callObj.CallWithContext( + ctx, "org.freedesktop.ModemManager1.Call.Accept", 0, + ) if call.Err != nil { return call.Err } @@ -132,9 +137,11 @@ func acceptCall(conn *dbus.Conn, callObj dbus.BusObject) error { } // getPhoneNum declines a call using a DBus connection -func declineCall(conn *dbus.Conn, callObj dbus.BusObject) error { +func declineCall(ctx context.Context, conn *dbus.Conn, callObj dbus.BusObject) error { // Call Hangup() method on DBus object - call := callObj.Call("org.freedesktop.ModemManager1.Call.Hangup", 0) + call := callObj.CallWithContext( + ctx, "org.freedesktop.ModemManager1.Call.Hangup", 0, + ) if call.Err != nil { return call.Err } diff --git a/dbus.go b/dbus.go index 6d05b5a..2db96a5 100644 --- a/dbus.go +++ b/dbus.go @@ -1,10 +1,14 @@ package main -import "github.com/godbus/dbus/v5" +import ( + "context" -func newSystemBusConn() (*dbus.Conn, error) { + "github.com/godbus/dbus/v5" +) + +func newSystemBusConn(ctx context.Context) (*dbus.Conn, error) { // Connect to dbus session bus - conn, err := dbus.SystemBusPrivate() + conn, err := dbus.SystemBusPrivate(dbus.WithContext(ctx)) if err != nil { return nil, err } @@ -19,9 +23,9 @@ func newSystemBusConn() (*dbus.Conn, error) { return conn, nil } -func newSessionBusConn() (*dbus.Conn, error) { +func newSessionBusConn(ctx context.Context) (*dbus.Conn, error) { // Connect to dbus session bus - conn, err := dbus.SessionBusPrivate() + conn, err := dbus.SessionBusPrivate(dbus.WithContext(ctx)) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index 11a8d14..825bd36 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-20220505193916-1533865e4c42 + go.arsenm.dev/infinitime v0.0.0-20220511202257-9ed74726c478 go.arsenm.dev/lrpc v0.0.0-20220510090735-af77b121f888 golang.org/x/text v0.3.7 modernc.org/sqlite v1.17.2 diff --git a/go.sum b/go.sum index 5b56255..7110a47 100644 --- a/go.sum +++ b/go.sum @@ -396,8 +396,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-20220505193916-1533865e4c42 h1:t3gXRa6TEPZ7mOGxkccYke7afkVe5qL+DGHFPkHF+WI= -go.arsenm.dev/infinitime v0.0.0-20220505193916-1533865e4c42/go.mod h1:1cBQ3fp6QlRbSqu9kEBAHsVThINj31FtqHIYVsQ7wgg= +go.arsenm.dev/infinitime v0.0.0-20220511202257-9ed74726c478 h1:HO+fteXuSnnT7po1PhGJK6nk8qMAGN2RqDaVP4sRN8g= +go.arsenm.dev/infinitime v0.0.0-20220511202257-9ed74726c478/go.mod h1:1cBQ3fp6QlRbSqu9kEBAHsVThINj31FtqHIYVsQ7wgg= go.arsenm.dev/lrpc v0.0.0-20220510090735-af77b121f888 h1:WrcoTvWsmg5YHq/nWRBMdcRlNfFPfVtfi6eBEVyod8w= go.arsenm.dev/lrpc v0.0.0-20220510090735-af77b121f888/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 8c71a9a..a768446 100644 --- a/main.go +++ b/main.go @@ -19,11 +19,14 @@ package main import ( + "context" _ "embed" "flag" "fmt" "os" + "os/signal" "strconv" + "syscall" "time" "github.com/gen2brain/dlgs" @@ -74,8 +77,24 @@ func main() { LogLevel: level, } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + sigCh := make(chan os.Signal, 1) + go func() { + <-sigCh + cancel() + time.Sleep(200 * time.Millisecond) + os.Exit(0) + }() + signal.Notify( + sigCh, + syscall.SIGINT, + syscall.SIGTERM, + ) + // Connect to InfiniTime with default options - dev, err := infinitime.Connect(opts) + dev, err := infinitime.Connect(ctx, opts) if err != nil { log.Fatal().Err(err).Msg("Error connecting to InfiniTime") } @@ -136,25 +155,25 @@ func main() { } // Start control socket - err = initCallNotifs(dev) + err = initCallNotifs(ctx, dev) if err != nil { log.Error().Err(err).Msg("Error initializing call notifications") } // Initialize notification relay - err = initNotifRelay(dev) + err = initNotifRelay(ctx, dev) if err != nil { log.Error().Err(err).Msg("Error initializing notification relay") } // Initializa weather - err = initWeather(dev) + err = initWeather(ctx, dev) if err != nil { log.Error().Err(err).Msg("Error initializing weather") } // Initialize metrics collection - err = initMetrics(dev) + err = initMetrics(ctx, dev) if err != nil { log.Error().Err(err).Msg("Error intializing metrics collection") } diff --git a/metrics.go b/metrics.go index 13a12e2..57d45f0 100644 --- a/metrics.go +++ b/metrics.go @@ -1,6 +1,7 @@ package main import ( + "context" "database/sql" "path/filepath" "time" @@ -10,7 +11,7 @@ import ( _ "modernc.org/sqlite" ) -func initMetrics(dev *infinitime.Device) error { +func initMetrics(ctx context.Context, dev *infinitime.Device) error { // If metrics disabled, return nil if !k.Bool("metrics.enabled") { return nil @@ -49,7 +50,7 @@ func initMetrics(dev *infinitime.Device) error { // If heart rate metrics enabled in config if k.Bool("metrics.heartRate.enabled") { // Watch heart rate - heartRateCh, _, err := dev.WatchHeartRate() + heartRateCh, err := dev.WatchHeartRate(ctx) if err != nil { return err } @@ -67,7 +68,7 @@ func initMetrics(dev *infinitime.Device) error { // If step count metrics enabled in config if k.Bool("metrics.stepCount.enabled") { // Watch step count - stepCountCh, _, err := dev.WatchStepCount() + stepCountCh, err := dev.WatchStepCount(ctx) if err != nil { return err } @@ -85,7 +86,7 @@ func initMetrics(dev *infinitime.Device) error { // If battery level metrics enabled in config if k.Bool("metrics.battLevel.enabled") { // Watch battery level - battLevelCh, _, err := dev.WatchBatteryLevel() + battLevelCh, err := dev.WatchBatteryLevel(ctx) if err != nil { return err } @@ -103,7 +104,7 @@ func initMetrics(dev *infinitime.Device) error { // If motion metrics enabled in config if k.Bool("metrics.motion.enabled") { // Watch motion values - motionCh, _, err := dev.WatchMotion() + motionCh, err := dev.WatchMotion(ctx) if err != nil { return err } diff --git a/notifs.go b/notifs.go index 3a117f4..669a52c 100644 --- a/notifs.go +++ b/notifs.go @@ -19,6 +19,7 @@ package main import ( + "context" "fmt" "github.com/godbus/dbus/v5" @@ -27,9 +28,9 @@ import ( "go.arsenm.dev/itd/translit" ) -func initNotifRelay(dev *infinitime.Device) error { +func initNotifRelay(ctx context.Context, dev *infinitime.Device) error { // Connect to dbus session bus - bus, err := newSessionBusConn() + bus, err := newSessionBusConn(ctx) if err != nil { return err } @@ -40,7 +41,9 @@ func initNotifRelay(dev *infinitime.Device) error { } var flag uint = 0 // Becode monitor for notifications - call := bus.BusObject().Call("org.freedesktop.DBus.Monitoring.BecomeMonitor", 0, rules, flag) + call := bus.BusObject().CallWithContext( + ctx, "org.freedesktop.DBus.Monitoring.BecomeMonitor", 0, rules, flag, + ) if call.Err != nil { return call.Err } diff --git a/socket.go b/socket.go index c1514a2..89e4bb3 100644 --- a/socket.go +++ b/socket.go @@ -105,22 +105,15 @@ func (i *ITD) WatchHeartRate(ctx *server.Context) error { return err } - heartRateCh, cancel, err := i.dev.WatchHeartRate() + heartRateCh, err := i.dev.WatchHeartRate(ctx) if err != nil { return err } go func() { // For every heart rate value - for { - select { - case <-ctx.Done(): - // Stop notifications if done signal received - cancel() - return - case heartRate := <-heartRateCh: - ch <- heartRate - } + for heartRate := range heartRateCh { + ch <- heartRate } }() @@ -137,22 +130,15 @@ func (i *ITD) WatchBatteryLevel(ctx *server.Context) error { return err } - battLevelCh, cancel, err := i.dev.WatchBatteryLevel() + battLevelCh, err := i.dev.WatchBatteryLevel(ctx) if err != nil { return err } go func() { // For every heart rate value - for { - select { - case <-ctx.Done(): - // Stop notifications if done signal received - cancel() - return - case battLevel := <-battLevelCh: - ch <- battLevel - } + for battLevel := range battLevelCh { + ch <- battLevel } }() @@ -169,22 +155,15 @@ func (i *ITD) WatchMotion(ctx *server.Context) error { return err } - motionValsCh, cancel, err := i.dev.WatchMotion() + motionValsCh, err := i.dev.WatchMotion(ctx) if err != nil { return err } go func() { // For every heart rate value - for { - select { - case <-ctx.Done(): - // Stop notifications if done signal received - cancel() - return - case motionVals := <-motionValsCh: - ch <- motionVals - } + for motionVals := range motionValsCh { + ch <- motionVals } }() @@ -201,22 +180,15 @@ func (i *ITD) WatchStepCount(ctx *server.Context) error { return err } - stepCountCh, cancel, err := i.dev.WatchStepCount() + stepCountCh, err := i.dev.WatchStepCount(ctx) if err != nil { return err } go func() { // For every heart rate value - for { - select { - case <-ctx.Done(): - // Stop notifications if done signal received - cancel() - return - case stepCount := <-stepCountCh: - ch <- stepCount - } + for stepCount := range stepCountCh { + ch <- stepCount } }() diff --git a/weather.go b/weather.go index 5005f49..040c63e 100644 --- a/weather.go +++ b/weather.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "fmt" "math" @@ -60,13 +61,13 @@ type OSMData []struct { var sendWeatherCh = make(chan struct{}, 1) -func initWeather(dev *infinitime.Device) error { +func initWeather(ctx context.Context, dev *infinitime.Device) error { if !k.Bool("weather.enabled") { return nil } // Get location based on string in config - lat, lon, err := getLocation(k.String("weather.location")) + lat, lon, err := getLocation(ctx, k.String("weather.location")) if err != nil { return err } @@ -76,7 +77,7 @@ func initWeather(dev *infinitime.Device) error { go func() { for { // Attempt to get weather - data, err := getWeather(lat, lon) + data, err := getWeather(ctx, lat, lon) if err != nil { log.Warn().Err(err).Msg("Error getting weather data") // Wait 15 minutes before retrying @@ -181,10 +182,14 @@ func initWeather(dev *infinitime.Device) error { // getLocation returns the latitude and longitude // given a location -func getLocation(loc string) (lat, lon float64, err error) { +func getLocation(ctx context.Context, loc string) (lat, lon float64, err error) { // Create request URL and perform GET request reqURL := fmt.Sprintf("https://nominatim.openstreetmap.org/search.php?q=%s&format=jsonv2", url.QueryEscape(loc)) - res, err := http.Get(reqURL) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil) + if err != nil { + return + } + res, err := http.DefaultClient.Do(req) if err != nil { return } @@ -218,9 +223,10 @@ func getLocation(loc string) (lat, lon float64, err error) { } // getWeather gets weather data given a latitude and longitude -func getWeather(lat, lon float64) (*METResponse, error) { +func getWeather(ctx context.Context, lat, lon float64) (*METResponse, error) { // Create new GET request - req, err := http.NewRequest( + req, err := http.NewRequestWithContext( + ctx, http.MethodGet, fmt.Sprintf( "https://api.met.no/weatherapi/locationforecast/2.0/complete?lat=%.2f&lon=%.2f",