From f6458d1b8fd54df25fea204c38610357d48ca171 Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Sun, 22 Apr 2018 18:01:52 +0200 Subject: [PATCH] lib/config, lib/model: Include paused folders in cluster config (fixes #4897) --- lib/config/config.go | 15 ++++++---- lib/config/folderconfiguration.go | 14 ++++++++++ lib/config/wrapper.go | 7 +++++ lib/model/model.go | 46 +++++++++++++++---------------- lib/model/model_test.go | 26 +++++++++++++++++ 5 files changed, 79 insertions(+), 29 deletions(-) diff --git a/lib/config/config.go b/lib/config/config.go index 1cda1630d..86e991406 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -325,13 +325,18 @@ func (cfg *Configuration) clean() error { existingDevices[device.DeviceID] = true } - // Ensure that the device list is free from duplicates + // Ensure that the device list is + // - free from duplicates + // - sorted by ID cfg.Devices = ensureNoDuplicateDevices(cfg.Devices) - sort.Sort(DeviceConfigurationList(cfg.Devices)) - // Ensure that any loose devices are not present in the wrong places - // Ensure that there are no duplicate devices - // Ensure that the versioning configuration parameter map is not nil + + // Ensure that the folder list is sorted by ID + sort.Sort(FolderConfigurationList(cfg.Folders)) + // Ensure that in all folder configs + // - any loose devices are not present in the wrong places + // - there are no duplicate devices + // - the versioning configuration parameter map is not nil for i := range cfg.Folders { cfg.Folders[i].Devices = ensureExistingDevices(cfg.Folders[i].Devices, existingDevices) cfg.Folders[i].Devices = ensureNoDuplicateFolderDevices(cfg.Folders[i].Devices) diff --git a/lib/config/folderconfiguration.go b/lib/config/folderconfiguration.go index d40ab6513..46d24c0ab 100644 --- a/lib/config/folderconfiguration.go +++ b/lib/config/folderconfiguration.go @@ -278,3 +278,17 @@ func (l FolderDeviceConfigurationList) Len() int { func (f *FolderConfiguration) CheckFreeSpace() (err error) { return checkFreeSpace(f.MinDiskFree, f.Filesystem()) } + +type FolderConfigurationList []FolderConfiguration + +func (l FolderConfigurationList) Len() int { + return len(l) +} + +func (l FolderConfigurationList) Less(a, b int) bool { + return l[a].ID < l[b].ID +} + +func (l FolderConfigurationList) Swap(a, b int) { + l[a], l[b] = l[b], l[a] +} diff --git a/lib/config/wrapper.go b/lib/config/wrapper.go index 058ca263d..4908adb2d 100644 --- a/lib/config/wrapper.go +++ b/lib/config/wrapper.go @@ -267,6 +267,13 @@ func (w *Wrapper) Folders() map[string]FolderConfiguration { return w.folderMap } +// FolderList returns a slice of folders. +func (w *Wrapper) FolderList() []FolderConfiguration { + w.mut.Lock() + defer w.mut.Unlock() + return append([]FolderConfiguration(nil), w.cfg.Folders...) +} + // SetFolder adds a new folder to the configuration, or overwrites an existing // folder with the same ID. func (w *Wrapper) SetFolder(fld FolderConfiguration) (Waiter, error) { diff --git a/lib/model/model.go b/lib/model/model.go index 0fb8860ed..c80149af5 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -2154,17 +2154,14 @@ func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster var message protocol.ClusterConfig m.fmut.RLock() - // The list of folders in the message is sorted, so we always get the - // same order. - folders := m.deviceFolders[device] - sort.Strings(folders) + folderFiles := m.folderFiles + m.fmut.RUnlock() - for _, folder := range folders { - folderCfg := m.cfg.Folders()[folder] - fs := m.folderFiles[folder] + var fs *db.FileSet + for _, folderCfg := range m.cfg.FolderList() { protocolFolder := protocol.Folder{ - ID: folder, + ID: folderCfg.ID, Label: folderCfg.Label, ReadOnly: folderCfg.Type == config.FolderTypeSendOnly, IgnorePermissions: folderCfg.IgnorePerms, @@ -2173,36 +2170,37 @@ func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster Paused: folderCfg.Paused, } - // Devices are sorted, so we always get the same order. - for _, device := range m.folderDevices.sortedDevices(folder) { - deviceCfg := m.cfg.Devices()[device] + if !folderCfg.Paused { + fs = folderFiles[folderCfg.ID] + } - var indexID protocol.IndexID - var maxSequence int64 - if device == m.id { - indexID = fs.IndexID(protocol.LocalDeviceID) - maxSequence = fs.Sequence(protocol.LocalDeviceID) - } else { - indexID = fs.IndexID(device) - maxSequence = fs.Sequence(device) - } + for _, device := range folderCfg.Devices { + deviceCfg, _ := m.cfg.Device(device.DeviceID) protocolDevice := protocol.Device{ - ID: device, + ID: deviceCfg.DeviceID, Name: deviceCfg.Name, Addresses: deviceCfg.Addresses, Compression: deviceCfg.Compression, CertName: deviceCfg.CertName, Introducer: deviceCfg.Introducer, - IndexID: indexID, - MaxSequence: maxSequence, + } + + if !folderCfg.Paused { + if deviceCfg.DeviceID == m.id { + protocolDevice.IndexID = fs.IndexID(protocol.LocalDeviceID) + protocolDevice.MaxSequence = fs.Sequence(protocol.LocalDeviceID) + } else { + protocolDevice.IndexID = fs.IndexID(deviceCfg.DeviceID) + protocolDevice.MaxSequence = fs.Sequence(deviceCfg.DeviceID) + } } protocolFolder.Devices = append(protocolFolder.Devices, protocolDevice) } + message.Folders = append(message.Folders, protocolFolder) } - m.fmut.RUnlock() return message } diff --git a/lib/model/model_test.go b/lib/model/model_test.go index 7b93affd0..a5223bac5 100644 --- a/lib/model/model_test.go +++ b/lib/model/model_test.go @@ -1043,6 +1043,32 @@ func TestIntroducer(t *testing.T) { } } +func TestIssue4897(t *testing.T) { + _, m := newState(config.Configuration{ + Devices: []config.DeviceConfiguration{ + { + DeviceID: device1, + Introducer: true, + }, + }, + Folders: []config.FolderConfiguration{ + { + ID: "folder1", + Path: "testdata", + Devices: []config.FolderDeviceConfiguration{ + {DeviceID: device1}, + }, + Paused: true, + }, + }, + }) + + cm := m.generateClusterConfig(device1) + if l := len(cm.Folders); l != 1 { + t.Errorf("Cluster config contains %v folders, expected 1", l) + } +} + func TestAutoAcceptRejected(t *testing.T) { // Nothing happens if AutoAcceptFolders not set tcfg := defaultAutoAcceptCfg.Copy()