From 57d668ed1de2db31ff46c628686aa7ca36d04f7f Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Thu, 21 Nov 2019 08:41:41 +0100 Subject: [PATCH] lib/config: Do introductions in a single config change (#6162) --- lib/model/model.go | 85 ++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/lib/model/model.go b/lib/model/model.go index 522a2c7e..e54bc3b1 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -1252,14 +1252,20 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon } if deviceCfg.Introducer { - foldersDevices, introduced := m.handleIntroductions(deviceCfg, cm) - if introduced { - changed = true - } - // 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) { + folders, devices, foldersDevices, introduced := m.handleIntroductions(deviceCfg, cm) + folders, devices, deintroduced := m.handleDeintroductions(deviceCfg, foldersDevices, folders, devices) + if introduced || deintroduced { 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 -func (m *model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm protocol.ClusterConfig) (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. +// handleIntroductions handles adding devices/folders that are shared by an introducer device +func (m *model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm protocol.ClusterConfig) (map[string]config.FolderConfiguration, map[protocol.DeviceID]config.DeviceConfiguration, folderDeviceSet, bool) { changed := false + folders := m.cfg.Folders() + devices := m.cfg.Devices() 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 // the folder. - fcfg, ok := m.cfg.Folder(folder.ID) + fcfg, ok := folders[folder.ID] if !ok { // Don't have this folder, carry on. continue } + folderChanged := false + for _, device := range folder.Devices { // No need to share with self. 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 { // 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) { // We already share the folder with this device, so // nothing to do. @@ -1315,36 +1322,41 @@ func (m *model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm DeviceID: device.ID, IntroducedBy: introducerCfg.DeviceID, }) - changed = true + folderChanged = true } - if changed { - m.cfg.SetFolder(fcfg) + if folderChanged { + 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 -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 devicesNotIntroduced := make(map[protocol.DeviceID]struct{}) - folders := m.cfg.FolderList() // Check if we should unshare some folders, if the introducer has unshared them. - for i := range folders { - for k := 0; k < len(folders[i].Devices); k++ { - if folders[i].Devices[k].IntroducedBy != introducerCfg.DeviceID { - devicesNotIntroduced[folders[i].Devices[k].DeviceID] = struct{}{} + for folderID, folderCfg := range folders { + for k := 0; k < len(folderCfg.Devices); k++ { + if folderCfg.Devices[k].IntroducedBy != introducerCfg.DeviceID { + devicesNotIntroduced[folderCfg.Devices[k].DeviceID] = struct{}{} 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 // introducer with the device that was introduced to us. // 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) - folders[i].Devices = append(folders[i].Devices[:k], folders[i].Devices[k+1:]...) + 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) + folderCfg.Devices = append(folderCfg.Devices[:k], folderCfg.Devices[k+1:]...) + folders[folderID] = folderCfg k-- 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 // shares any folder with them. Yet do not remove if we share other // folders that haven't been introduced by the introducer. - devMap := m.cfg.Devices() - devices := make([]config.DeviceConfiguration, 0, len(devMap)) - for deviceID, device := range devMap { + for deviceID, device := range devices { if device.IntroducedBy == introducerCfg.DeviceID { if !foldersDevices.hasDevice(deviceID) { if _, ok := devicesNotIntroduced[deviceID]; !ok { @@ -1364,22 +1374,15 @@ func (m *model) handleDeintroductions(introducerCfg config.DeviceConfiguration, // device, remove the device. l.Infof("Removing device %v as introducer %v no longer shares any folders with that device", deviceID, device.IntroducedBy) changed = true + delete(devices, deviceID) 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) } } - devices = append(devices, device) } - if changed { - cfg := m.cfg.RawCopy() - cfg.Folders = folders - cfg.Devices = devices - m.cfg.Replace(cfg) - } - - return changed + return folders, devices, changed } // 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"} for _, addr := range device.Addresses { if addr != "dynamic" { @@ -1455,7 +1458,7 @@ func (m *model) introduceDevice(device protocol.Device, introducerCfg config.Dev newDeviceCfg.SkipIntroductionRemovals = device.SkipIntroductionRemovals } - m.cfg.SetDevice(newDeviceCfg) + return newDeviceCfg } // Closed is called when a connection has been closed