1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-07 22:18:30 -04:00

fix(geolocation): fetch IP location lazily so startup never contacts ip-api.com

fixes #3008
port 1.5
This commit is contained in:
bbedward
2026-08-07 19:54:21 -04:00
parent f16bdda969
commit a713485599
4 changed files with 45 additions and 55 deletions
+1 -31
View File
@@ -6,37 +6,7 @@ func NewClient() Client {
geoclueClient, err := newGeoClueClient() geoclueClient, err := newGeoClueClient()
if err != nil { if err != nil {
log.Warnf("GeoClue2 unavailable: %v", err) log.Warnf("GeoClue2 unavailable: %v", err)
return newSeededIpClient() return newIpClient()
} }
loc, _ := geoclueClient.GetLocation()
if loc.Latitude != 0 || loc.Longitude != 0 {
log.Info("Using GeoClue2 location")
return geoclueClient
}
log.Info("GeoClue2 has no fix yet, seeding with IP location")
ipLoc, err := fetchIPLocation()
if err != nil {
log.Warnf("IP location seed failed: %v", err)
return geoclueClient
}
log.Info("Seeded GeoClue2 with IP location")
geoclueClient.SeedLocation(Location{Latitude: ipLoc.Latitude, Longitude: ipLoc.Longitude})
return geoclueClient return geoclueClient
} }
func newSeededIpClient() *IpClient {
client := newIpClient()
ipLoc, err := fetchIPLocation()
if err != nil {
log.Warnf("IP location also failed: %v", err)
return client
}
log.Info("Using IP location")
client.currLocation.Latitude = ipLoc.Latitude
client.currLocation.Longitude = ipLoc.Longitude
return client
}
+22 -6
View File
@@ -34,6 +34,7 @@ const (
type GeoClueClient struct { type GeoClueClient struct {
currLocation *Location currLocation *Location
locationMutex sync.RWMutex locationMutex sync.RWMutex
seedOnce sync.Once
dbusConn *dbus.Conn dbusConn *dbus.Conn
clientPath dbus.ObjectPath clientPath dbus.ObjectPath
@@ -230,14 +231,29 @@ func (c *GeoClueClient) SeedLocation(loc Location) {
} }
func (c *GeoClueClient) GetLocation() (Location, error) { func (c *GeoClueClient) GetLocation() (Location, error) {
loc := c.currentLocation()
if loc.Latitude != 0 || loc.Longitude != 0 {
return loc, nil
}
c.seedOnce.Do(func() {
ipLoc, err := fetchIPLocation()
if err != nil {
log.Warnf("GeoClue2 has no fix, IP location seed failed: %v", err)
return
}
log.Info("Seeded GeoClue2 with IP location")
c.SeedLocation(Location{Latitude: ipLoc.Latitude, Longitude: ipLoc.Longitude})
})
return c.currentLocation(), nil
}
func (c *GeoClueClient) currentLocation() Location {
c.locationMutex.RLock() c.locationMutex.RLock()
defer c.locationMutex.RUnlock() defer c.locationMutex.RUnlock()
if c.currLocation == nil { if c.currLocation == nil {
return Location{ return Location{}
Latitude: 0.0,
Longitude: 0.0,
}, nil
} }
stateCopy := *c.currLocation return *c.currLocation
return stateCopy, nil
} }
+20 -17
View File
@@ -8,24 +8,11 @@ import (
) )
func NewManager(client geolocation.Client) (*Manager, error) { func NewManager(client geolocation.Client) (*Manager, error) {
currLocation, err := client.GetLocation()
if err != nil {
log.Warnf("Failed to get initial location: %v", err)
}
m := &Manager{ m := &Manager{
client: client, client: client,
dirty: make(chan struct{}), dirty: make(chan struct{}),
stopChan: make(chan struct{}), stopChan: make(chan struct{}),
state: &State{},
state: &State{
Latitude: currLocation.Latitude,
Longitude: currLocation.Longitude,
},
}
if err := m.startSignalPump(); err != nil {
return nil, err
} }
m.notifierWg.Add(1) m.notifierWg.Add(1)
@@ -34,6 +21,22 @@ func NewManager(client geolocation.Client) (*Manager, error) {
return m, nil return m, nil
} }
// The geolocation client may fetch IP location on first use, so nothing
// touches it until a consumer actually asks for location data.
func (m *Manager) ensureStarted() {
m.startOnce.Do(func() {
go func() {
currLocation, err := m.client.GetLocation()
if err != nil {
log.Warnf("Failed to get initial location: %v", err)
} else {
m.handleLocationChange(currLocation)
}
m.startSignalPump()
}()
})
}
func (m *Manager) Close() { func (m *Manager) Close() {
close(m.stopChan) close(m.stopChan)
m.notifierWg.Wait() m.notifierWg.Wait()
@@ -48,6 +51,7 @@ func (m *Manager) Close() {
} }
func (m *Manager) Subscribe(id string) chan State { func (m *Manager) Subscribe(id string) chan State {
m.ensureStarted()
ch := make(chan State, 64) ch := make(chan State, 64)
m.subscribers.Store(id, ch) m.subscribers.Store(id, ch)
return ch return ch
@@ -59,7 +63,7 @@ func (m *Manager) Unsubscribe(id string) {
} }
} }
func (m *Manager) startSignalPump() error { func (m *Manager) startSignalPump() {
m.sigWG.Add(1) m.sigWG.Add(1)
go func() { go func() {
defer m.sigWG.Done() defer m.sigWG.Done()
@@ -80,8 +84,6 @@ func (m *Manager) startSignalPump() error {
} }
} }
}() }()
return nil
} }
func (m *Manager) handleLocationChange(location geolocation.Location) { func (m *Manager) handleLocationChange(location geolocation.Location) {
@@ -102,6 +104,7 @@ func (m *Manager) notifySubscribers() {
} }
func (m *Manager) GetState() State { func (m *Manager) GetState() State {
m.ensureStarted()
m.stateMutex.RLock() m.stateMutex.RLock()
defer m.stateMutex.RUnlock() defer m.stateMutex.RUnlock()
if m.state == nil { if m.state == nil {
+2 -1
View File
@@ -16,7 +16,8 @@ type Manager struct {
state *State state *State
stateMutex sync.RWMutex stateMutex sync.RWMutex
client geolocation.Client client geolocation.Client
startOnce sync.Once
stopChan chan struct{} stopChan chan struct{}
sigWG sync.WaitGroup sigWG sync.WaitGroup