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:
@@ -6,37 +6,7 @@ func NewClient() Client {
|
||||
geoclueClient, err := newGeoClueClient()
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ const (
|
||||
type GeoClueClient struct {
|
||||
currLocation *Location
|
||||
locationMutex sync.RWMutex
|
||||
seedOnce sync.Once
|
||||
|
||||
dbusConn *dbus.Conn
|
||||
clientPath dbus.ObjectPath
|
||||
@@ -230,14 +231,29 @@ func (c *GeoClueClient) SeedLocation(loc Location) {
|
||||
}
|
||||
|
||||
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()
|
||||
defer c.locationMutex.RUnlock()
|
||||
if c.currLocation == nil {
|
||||
return Location{
|
||||
Latitude: 0.0,
|
||||
Longitude: 0.0,
|
||||
}, nil
|
||||
return Location{}
|
||||
}
|
||||
stateCopy := *c.currLocation
|
||||
return stateCopy, nil
|
||||
return *c.currLocation
|
||||
}
|
||||
|
||||
@@ -8,24 +8,11 @@ import (
|
||||
)
|
||||
|
||||
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{
|
||||
client: client,
|
||||
dirty: make(chan struct{}),
|
||||
stopChan: make(chan struct{}),
|
||||
|
||||
state: &State{
|
||||
Latitude: currLocation.Latitude,
|
||||
Longitude: currLocation.Longitude,
|
||||
},
|
||||
}
|
||||
|
||||
if err := m.startSignalPump(); err != nil {
|
||||
return nil, err
|
||||
state: &State{},
|
||||
}
|
||||
|
||||
m.notifierWg.Add(1)
|
||||
@@ -34,6 +21,22 @@ func NewManager(client geolocation.Client) (*Manager, error) {
|
||||
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() {
|
||||
close(m.stopChan)
|
||||
m.notifierWg.Wait()
|
||||
@@ -48,6 +51,7 @@ func (m *Manager) Close() {
|
||||
}
|
||||
|
||||
func (m *Manager) Subscribe(id string) chan State {
|
||||
m.ensureStarted()
|
||||
ch := make(chan State, 64)
|
||||
m.subscribers.Store(id, 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)
|
||||
go func() {
|
||||
defer m.sigWG.Done()
|
||||
@@ -80,8 +84,6 @@ func (m *Manager) startSignalPump() error {
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) handleLocationChange(location geolocation.Location) {
|
||||
@@ -102,6 +104,7 @@ func (m *Manager) notifySubscribers() {
|
||||
}
|
||||
|
||||
func (m *Manager) GetState() State {
|
||||
m.ensureStarted()
|
||||
m.stateMutex.RLock()
|
||||
defer m.stateMutex.RUnlock()
|
||||
if m.state == nil {
|
||||
|
||||
@@ -16,7 +16,8 @@ type Manager struct {
|
||||
state *State
|
||||
stateMutex sync.RWMutex
|
||||
|
||||
client geolocation.Client
|
||||
client geolocation.Client
|
||||
startOnce sync.Once
|
||||
|
||||
stopChan chan struct{}
|
||||
sigWG sync.WaitGroup
|
||||
|
||||
Reference in New Issue
Block a user