lib/config: Do introductions in a single config change (#6162)

This commit is contained in:
Simon Frei 2019-11-21 08:41:41 +01:00 committed by GitHub
parent 90d85fd0a2
commit 57d668ed1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1252,14 +1252,20 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
} }
if deviceCfg.Introducer { if deviceCfg.Introducer {
foldersDevices, introduced := m.handleIntroductions(deviceCfg, cm) folders, devices, foldersDevices, introduced := m.handleIntroductions(deviceCfg, cm)
if introduced { folders, devices, deintroduced := m.handleDeintroductions(deviceCfg, foldersDevices, folders, devices)
changed = true if introduced || deintroduced {
}
// If permitted, check if the introducer has unshare devices/folders with
// some of the devices/folders that we know were introduced to us by him.
if !deviceCfg.SkipIntroductionRemovals && m.handleDeintroductions(deviceCfg, cm, foldersDevices) {
changed = true changed = true
cfg := m.cfg.RawCopy()
cfg.Folders = make([]config.FolderConfiguration, 0, len(folders))
for _, fcfg := range folders {
cfg.Folders = append(cfg.Folders, fcfg)
}
cfg.Devices = make([]config.DeviceConfiguration, len(devices))
for _, dcfg := range devices {
cfg.Devices = append(cfg.Devices, dcfg)
}
m.cfg.Replace(cfg)
} }
} }
@ -1270,12 +1276,11 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
} }
} }
// handleIntroductions handles adding devices/shares that are shared by an introducer device // handleIntroductions handles adding devices/folders that are shared by an introducer device
func (m *model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm protocol.ClusterConfig) (folderDeviceSet, bool) { func (m *model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm protocol.ClusterConfig) (map[string]config.FolderConfiguration, map[protocol.DeviceID]config.DeviceConfiguration, folderDeviceSet, bool) {
// This device is an introducer. Go through the announced lists of folders
// and devices and add what we are missing, remove what we have extra that
// has been introducer by the introducer.
changed := false changed := false
folders := m.cfg.Folders()
devices := m.cfg.Devices()
foldersDevices := make(folderDeviceSet) foldersDevices := make(folderDeviceSet)
@ -1285,12 +1290,14 @@ func (m *model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm
// with devices that we have in common, yet are currently not sharing // with devices that we have in common, yet are currently not sharing
// the folder. // the folder.
fcfg, ok := m.cfg.Folder(folder.ID) fcfg, ok := folders[folder.ID]
if !ok { if !ok {
// Don't have this folder, carry on. // Don't have this folder, carry on.
continue continue
} }
folderChanged := false
for _, device := range folder.Devices { for _, device := range folder.Devices {
// No need to share with self. // No need to share with self.
if device.ID == m.id { if device.ID == m.id {
@ -1301,7 +1308,7 @@ func (m *model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm
if _, ok := m.cfg.Devices()[device.ID]; !ok { if _, ok := m.cfg.Devices()[device.ID]; !ok {
// The device is currently unknown. Add it to the config. // The device is currently unknown. Add it to the config.
m.introduceDevice(device, introducerCfg) devices[device.ID] = m.introduceDevice(device, introducerCfg)
} else if fcfg.SharedWith(device.ID) { } else if fcfg.SharedWith(device.ID) {
// We already share the folder with this device, so // We already share the folder with this device, so
// nothing to do. // nothing to do.
@ -1315,36 +1322,41 @@ func (m *model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm
DeviceID: device.ID, DeviceID: device.ID,
IntroducedBy: introducerCfg.DeviceID, IntroducedBy: introducerCfg.DeviceID,
}) })
changed = true folderChanged = true
} }
if changed { if folderChanged {
m.cfg.SetFolder(fcfg) folders[fcfg.ID] = fcfg
changed = true
} }
} }
return foldersDevices, changed return folders, devices, foldersDevices, changed
} }
// handleDeintroductions handles removals of devices/shares that are removed by an introducer device // handleDeintroductions handles removals of devices/shares that are removed by an introducer device
func (m *model) handleDeintroductions(introducerCfg config.DeviceConfiguration, cm protocol.ClusterConfig, foldersDevices folderDeviceSet) bool { func (m *model) handleDeintroductions(introducerCfg config.DeviceConfiguration, foldersDevices folderDeviceSet, folders map[string]config.FolderConfiguration, devices map[protocol.DeviceID]config.DeviceConfiguration) (map[string]config.FolderConfiguration, map[protocol.DeviceID]config.DeviceConfiguration, bool) {
if introducerCfg.SkipIntroductionRemovals {
return folders, devices, false
}
changed := false changed := false
devicesNotIntroduced := make(map[protocol.DeviceID]struct{}) devicesNotIntroduced := make(map[protocol.DeviceID]struct{})
folders := m.cfg.FolderList()
// Check if we should unshare some folders, if the introducer has unshared them. // Check if we should unshare some folders, if the introducer has unshared them.
for i := range folders { for folderID, folderCfg := range folders {
for k := 0; k < len(folders[i].Devices); k++ { for k := 0; k < len(folderCfg.Devices); k++ {
if folders[i].Devices[k].IntroducedBy != introducerCfg.DeviceID { if folderCfg.Devices[k].IntroducedBy != introducerCfg.DeviceID {
devicesNotIntroduced[folders[i].Devices[k].DeviceID] = struct{}{} devicesNotIntroduced[folderCfg.Devices[k].DeviceID] = struct{}{}
continue continue
} }
if !foldersDevices.has(folders[i].Devices[k].DeviceID, folders[i].ID) { if !foldersDevices.has(folderCfg.Devices[k].DeviceID, folderCfg.ID) {
// We could not find that folder shared on the // We could not find that folder shared on the
// introducer with the device that was introduced to us. // introducer with the device that was introduced to us.
// We should follow and unshare as well. // We should follow and unshare as well.
l.Infof("Unsharing folder %s with %v as introducer %v no longer shares the folder with that device", folders[i].Description(), folders[i].Devices[k].DeviceID, folders[i].Devices[k].IntroducedBy) l.Infof("Unsharing folder %s with %v as introducer %v no longer shares the folder with that device", folderCfg.Description(), folderCfg.Devices[k].DeviceID, folderCfg.Devices[k].IntroducedBy)
folders[i].Devices = append(folders[i].Devices[:k], folders[i].Devices[k+1:]...) folderCfg.Devices = append(folderCfg.Devices[:k], folderCfg.Devices[k+1:]...)
folders[folderID] = folderCfg
k-- k--
changed = true changed = true
} }
@ -1354,9 +1366,7 @@ func (m *model) handleDeintroductions(introducerCfg config.DeviceConfiguration,
// Check if we should remove some devices, if the introducer no longer // Check if we should remove some devices, if the introducer no longer
// shares any folder with them. Yet do not remove if we share other // shares any folder with them. Yet do not remove if we share other
// folders that haven't been introduced by the introducer. // folders that haven't been introduced by the introducer.
devMap := m.cfg.Devices() for deviceID, device := range devices {
devices := make([]config.DeviceConfiguration, 0, len(devMap))
for deviceID, device := range devMap {
if device.IntroducedBy == introducerCfg.DeviceID { if device.IntroducedBy == introducerCfg.DeviceID {
if !foldersDevices.hasDevice(deviceID) { if !foldersDevices.hasDevice(deviceID) {
if _, ok := devicesNotIntroduced[deviceID]; !ok { if _, ok := devicesNotIntroduced[deviceID]; !ok {
@ -1364,22 +1374,15 @@ func (m *model) handleDeintroductions(introducerCfg config.DeviceConfiguration,
// device, remove the device. // device, remove the device.
l.Infof("Removing device %v as introducer %v no longer shares any folders with that device", deviceID, device.IntroducedBy) l.Infof("Removing device %v as introducer %v no longer shares any folders with that device", deviceID, device.IntroducedBy)
changed = true changed = true
delete(devices, deviceID)
continue continue
} }
l.Infof("Would have removed %v as %v no longer shares any folders, yet there are other folders that are shared with this device that haven't been introduced by this introducer.", deviceID, device.IntroducedBy) l.Infof("Would have removed %v as %v no longer shares any folders, yet there are other folders that are shared with this device that haven't been introduced by this introducer.", deviceID, device.IntroducedBy)
} }
} }
devices = append(devices, device)
} }
if changed { return folders, devices, changed
cfg := m.cfg.RawCopy()
cfg.Folders = folders
cfg.Devices = devices
m.cfg.Replace(cfg)
}
return changed
} }
// handleAutoAccepts handles adding and sharing folders for devices that have // handleAutoAccepts handles adding and sharing folders for devices that have
@ -1430,7 +1433,7 @@ func (m *model) handleAutoAccepts(deviceCfg config.DeviceConfiguration, folder p
} }
} }
func (m *model) introduceDevice(device protocol.Device, introducerCfg config.DeviceConfiguration) { func (m *model) introduceDevice(device protocol.Device, introducerCfg config.DeviceConfiguration) config.DeviceConfiguration {
addresses := []string{"dynamic"} addresses := []string{"dynamic"}
for _, addr := range device.Addresses { for _, addr := range device.Addresses {
if addr != "dynamic" { if addr != "dynamic" {
@ -1455,7 +1458,7 @@ func (m *model) introduceDevice(device protocol.Device, introducerCfg config.Dev
newDeviceCfg.SkipIntroductionRemovals = device.SkipIntroductionRemovals newDeviceCfg.SkipIntroductionRemovals = device.SkipIntroductionRemovals
} }
m.cfg.SetDevice(newDeviceCfg) return newDeviceCfg
} }
// Closed is called when a connection has been closed // Closed is called when a connection has been closed