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()
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user