wip: migrate to mono-repo. SPN has already been moved to spn/
This commit is contained in:
165
spn/navigator/map.go
Normal file
165
spn/navigator/map.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package navigator
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/safing/portbase/database"
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/service/intel/geoip"
|
||||
"github.com/safing/portmaster/spn/docks"
|
||||
"github.com/safing/portmaster/spn/hub"
|
||||
)
|
||||
|
||||
// Map represent a collection of Pins and their relationship and status.
|
||||
type Map struct {
|
||||
sync.RWMutex
|
||||
Name string
|
||||
|
||||
all map[string]*Pin
|
||||
intel *hub.Intel
|
||||
regions []*Region
|
||||
|
||||
home *Pin
|
||||
homeTerminal *docks.CraneTerminal
|
||||
|
||||
measuringEnabled bool
|
||||
hubUpdateHook *database.RegisteredHook
|
||||
|
||||
// analysisLock guards access to all of this map's Pin.analysis,
|
||||
// regardedPins and the lastDesegrationAttempt fields.
|
||||
analysisLock sync.Mutex
|
||||
regardedPins []*Pin
|
||||
lastDesegrationAttempt time.Time
|
||||
}
|
||||
|
||||
// NewMap returns a new and empty Map.
|
||||
func NewMap(name string, enableMeasuring bool) *Map {
|
||||
m := &Map{
|
||||
Name: name,
|
||||
all: make(map[string]*Pin),
|
||||
measuringEnabled: enableMeasuring,
|
||||
}
|
||||
addMapToAPI(m)
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// Close removes the map's integration, taking it "offline".
|
||||
func (m *Map) Close() {
|
||||
removeMapFromAPI(m.Name)
|
||||
}
|
||||
|
||||
// GetPin returns the Pin of the Hub with the given ID.
|
||||
func (m *Map) GetPin(hubID string) (pin *Pin, ok bool) {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
pin, ok = m.all[hubID]
|
||||
return
|
||||
}
|
||||
|
||||
// GetHome returns the current home and it's accompanying terminal.
|
||||
// Both may be nil.
|
||||
func (m *Map) GetHome() (*Pin, *docks.CraneTerminal) {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
return m.home, m.homeTerminal
|
||||
}
|
||||
|
||||
// SetHome sets the given hub as the new home. Optionally, a terminal may be
|
||||
// supplied to accompany the home hub.
|
||||
func (m *Map) SetHome(id string, t *docks.CraneTerminal) (ok bool) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
// Get pin from map.
|
||||
newHome, ok := m.all[id]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// Remove home hub state from all pins.
|
||||
for _, pin := range m.all {
|
||||
pin.removeStates(StateIsHomeHub)
|
||||
}
|
||||
|
||||
// Set pin as home.
|
||||
m.home = newHome
|
||||
m.homeTerminal = t
|
||||
m.home.addStates(StateIsHomeHub)
|
||||
|
||||
// Recalculate reachable.
|
||||
err := m.recalculateReachableHubs()
|
||||
if err != nil {
|
||||
log.Warningf("spn/navigator: failed to recalculate reachable hubs: %s", err)
|
||||
}
|
||||
|
||||
m.PushPinChanges()
|
||||
return true
|
||||
}
|
||||
|
||||
// GetAvailableCountries returns a map of countries including their information
|
||||
// where the map has pins suitable for the given type.
|
||||
func (m *Map) GetAvailableCountries(opts *Options, forType HubType) map[string]*geoip.CountryInfo {
|
||||
if opts == nil {
|
||||
opts = m.defaultOptions()
|
||||
}
|
||||
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
matcher := opts.Matcher(forType, m.intel)
|
||||
countries := make(map[string]*geoip.CountryInfo)
|
||||
for _, pin := range m.all {
|
||||
if !matcher(pin) {
|
||||
continue
|
||||
}
|
||||
if pin.LocationV4 != nil && countries[pin.LocationV4.Country.Code] == nil {
|
||||
countries[pin.LocationV4.Country.Code] = &pin.LocationV4.Country
|
||||
}
|
||||
if pin.LocationV6 != nil && countries[pin.LocationV6.Country.Code] == nil {
|
||||
countries[pin.LocationV6.Country.Code] = &pin.LocationV6.Country
|
||||
}
|
||||
}
|
||||
|
||||
return countries
|
||||
}
|
||||
|
||||
// isEmpty returns whether the Map is regarded as empty.
|
||||
func (m *Map) isEmpty() bool {
|
||||
if m.home != nil {
|
||||
// When a home hub is set, we also regard a map with only one entry to be
|
||||
// empty, as this will be the case for Hubs, which will have their own
|
||||
// entry in the Map.
|
||||
return len(m.all) <= 1
|
||||
}
|
||||
|
||||
return len(m.all) == 0
|
||||
}
|
||||
|
||||
func (m *Map) pinList(lockMap bool) []*Pin {
|
||||
if lockMap {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
}
|
||||
|
||||
// Copy into slice.
|
||||
list := make([]*Pin, 0, len(m.all))
|
||||
for _, pin := range m.all {
|
||||
list = append(list, pin)
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
func (m *Map) sortedPins(lockMap bool) []*Pin {
|
||||
// Get list.
|
||||
list := m.pinList(lockMap)
|
||||
|
||||
// Sort list.
|
||||
sort.Sort(sortByPinID(list))
|
||||
return list
|
||||
}
|
||||
Reference in New Issue
Block a user