mirror of
https://github.com/octoleo/syncthing.git
synced 2024-12-22 10:58:57 +00:00
all: Refactor preparing configuration (#7127)
This commit is contained in:
parent
641b7aee38
commit
24af89c8e2
@ -185,7 +185,7 @@ func main() {
|
||||
log.Println("ID:", id)
|
||||
}
|
||||
|
||||
wrapper := config.Wrap("config", config.New(id), events.NoopLogger)
|
||||
wrapper := config.Wrap("config", config.New(id), id, events.NoopLogger)
|
||||
wrapper.SetOptions(config.OptionsConfiguration{
|
||||
NATLeaseM: natLease,
|
||||
NATRenewalM: natRenewal,
|
||||
|
@ -113,7 +113,7 @@ func TestStopAfterBrokenConfig(t *testing.T) {
|
||||
RawUseTLS: false,
|
||||
},
|
||||
}
|
||||
w := config.Wrap("/dev/null", cfg, events.NoopLogger)
|
||||
w := config.Wrap("/dev/null", cfg, protocol.LocalDeviceID, events.NoopLogger)
|
||||
|
||||
srv := New(protocol.LocalDeviceID, w, "", "syncthing", nil, nil, nil, events.NoopLogger, nil, nil, nil, nil, nil, nil, false).(*service)
|
||||
defer os.Remove(token)
|
||||
@ -1251,7 +1251,7 @@ func TestConfigChanges(t *testing.T) {
|
||||
panic(err)
|
||||
}
|
||||
defer os.Remove(tmpFile.Name())
|
||||
w := config.Wrap(tmpFile.Name(), cfg, events.NoopLogger)
|
||||
w := config.Wrap(tmpFile.Name(), cfg, protocol.LocalDeviceID, events.NoopLogger)
|
||||
tmpFile.Close()
|
||||
baseURL, cancel, err := startHTTP(w)
|
||||
if err != nil {
|
||||
|
@ -142,6 +142,10 @@ func (c *mockedConfig) StunServers() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *mockedConfig) MyID() protocol.DeviceID {
|
||||
return protocol.DeviceID{}
|
||||
}
|
||||
|
||||
type noopWaiter struct{}
|
||||
|
||||
func (noopWaiter) Wait() {}
|
||||
|
@ -44,7 +44,7 @@ func (validationError) String() string {
|
||||
func TestReplaceCommit(t *testing.T) {
|
||||
t.Skip("broken, fails randomly, #3834")
|
||||
|
||||
w := wrap("/dev/null", Configuration{Version: 0})
|
||||
w := wrap("/dev/null", Configuration{Version: 0}, device1)
|
||||
if w.RawCopy().Version != 0 {
|
||||
t.Fatal("Config incorrect")
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ import (
|
||||
|
||||
"github.com/syncthing/syncthing/lib/fs"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/rand"
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
)
|
||||
|
||||
@ -105,8 +104,6 @@ func New(myID protocol.DeviceID) Configuration {
|
||||
cfg.Options.UnackedNotificationIDs = []string{"authenticationUserAndPassword"}
|
||||
|
||||
util.SetDefaults(&cfg)
|
||||
util.SetDefaults(&cfg.Options)
|
||||
util.SetDefaults(&cfg.GUI)
|
||||
|
||||
// Can't happen.
|
||||
if err := cfg.prepare(myID); err != nil {
|
||||
@ -152,8 +149,6 @@ func ReadXML(r io.Reader, myID protocol.DeviceID) (Configuration, int, error) {
|
||||
var cfg xmlConfiguration
|
||||
|
||||
util.SetDefaults(&cfg)
|
||||
util.SetDefaults(&cfg.Options)
|
||||
util.SetDefaults(&cfg.GUI)
|
||||
|
||||
if err := xml.NewDecoder(r).Decode(&cfg); err != nil {
|
||||
return Configuration{}, 0, err
|
||||
@ -171,8 +166,6 @@ func ReadJSON(r io.Reader, myID protocol.DeviceID) (Configuration, error) {
|
||||
var cfg Configuration
|
||||
|
||||
util.SetDefaults(&cfg)
|
||||
util.SetDefaults(&cfg.Options)
|
||||
util.SetDefaults(&cfg.GUI)
|
||||
|
||||
bs, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
@ -230,38 +223,61 @@ func (cfg *Configuration) WriteXML(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (cfg *Configuration) prepare(myID protocol.DeviceID) error {
|
||||
var myName string
|
||||
cfg.ensureMyDevice(myID)
|
||||
|
||||
// Ensure this device is present in the config
|
||||
for _, device := range cfg.Devices {
|
||||
if device.DeviceID == myID {
|
||||
goto found
|
||||
}
|
||||
}
|
||||
|
||||
myName, _ = os.Hostname()
|
||||
cfg.Devices = append(cfg.Devices, DeviceConfiguration{
|
||||
DeviceID: myID,
|
||||
Name: myName,
|
||||
})
|
||||
|
||||
found:
|
||||
|
||||
if err := cfg.clean(); err != nil {
|
||||
existingDevices, err := cfg.prepareFoldersAndDevices(myID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure that we are part of the devices
|
||||
for i := range cfg.Folders {
|
||||
cfg.Folders[i].Devices = ensureDevicePresent(cfg.Folders[i].Devices, myID)
|
||||
}
|
||||
cfg.GUI.prepare()
|
||||
|
||||
guiPWIsSet := cfg.GUI.User != "" && cfg.GUI.Password != ""
|
||||
cfg.Options.prepare(guiPWIsSet)
|
||||
|
||||
ignoredDevices := cfg.prepareIgnoredDevices(existingDevices)
|
||||
|
||||
cfg.preparePendingDevices(existingDevices, ignoredDevices)
|
||||
|
||||
cfg.removeDeprecatedProtocols()
|
||||
|
||||
util.FillNilExceptDeprecated(cfg)
|
||||
|
||||
// TestIssue1750 relies on migrations happening after preparing options.
|
||||
cfg.applyMigrations()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *Configuration) clean() error {
|
||||
util.FillNilSlices(&cfg.Options)
|
||||
func (cfg *Configuration) ensureMyDevice(myID protocol.DeviceID) {
|
||||
// Ensure this device is present in the config
|
||||
for _, device := range cfg.Devices {
|
||||
if device.DeviceID == myID {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
myName, _ := os.Hostname()
|
||||
cfg.Devices = append(cfg.Devices, DeviceConfiguration{
|
||||
DeviceID: myID,
|
||||
Name: myName,
|
||||
})
|
||||
}
|
||||
|
||||
func (cfg *Configuration) prepareFoldersAndDevices(myID protocol.DeviceID) (map[protocol.DeviceID]bool, error) {
|
||||
existingDevices := cfg.prepareDeviceList()
|
||||
|
||||
sharedFolders, err := cfg.prepareFolders(myID, existingDevices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg.prepareDevices(sharedFolders)
|
||||
|
||||
return existingDevices, nil
|
||||
}
|
||||
|
||||
func (cfg *Configuration) prepareDeviceList() map[protocol.DeviceID]bool {
|
||||
// Ensure that the device list is
|
||||
// - free from duplicates
|
||||
// - no devices with empty ID
|
||||
@ -272,89 +288,62 @@ func (cfg *Configuration) clean() error {
|
||||
return cfg.Devices[a].DeviceID.Compare(cfg.Devices[b].DeviceID) == -1
|
||||
})
|
||||
|
||||
// Build a list of available devices
|
||||
existingDevices := make(map[protocol.DeviceID]bool, len(cfg.Devices))
|
||||
for _, device := range cfg.Devices {
|
||||
existingDevices[device.DeviceID] = true
|
||||
}
|
||||
return existingDevices
|
||||
}
|
||||
|
||||
func (cfg *Configuration) prepareFolders(myID protocol.DeviceID, existingDevices map[protocol.DeviceID]bool) (map[protocol.DeviceID][]string, error) {
|
||||
// Prepare folders and check for duplicates. Duplicates are bad and
|
||||
// dangerous, can't currently be resolved in the GUI, and shouldn't
|
||||
// happen when configured by the GUI. We return with an error in that
|
||||
// situation.
|
||||
existingFolders := make(map[string]*FolderConfiguration)
|
||||
sharedFolders := make(map[protocol.DeviceID][]string, len(cfg.Devices))
|
||||
existingFolders := make(map[string]*FolderConfiguration, len(cfg.Folders))
|
||||
for i := range cfg.Folders {
|
||||
folder := &cfg.Folders[i]
|
||||
folder.prepare()
|
||||
|
||||
if folder.ID == "" {
|
||||
return errFolderIDEmpty
|
||||
return nil, errFolderIDEmpty
|
||||
}
|
||||
|
||||
if folder.Path == "" {
|
||||
return fmt.Errorf("folder %q: %w", folder.ID, errFolderPathEmpty)
|
||||
return nil, fmt.Errorf("folder %q: %w", folder.ID, errFolderPathEmpty)
|
||||
}
|
||||
|
||||
if _, ok := existingFolders[folder.ID]; ok {
|
||||
return fmt.Errorf("folder %q: %w", folder.ID, errFolderIDDuplicate)
|
||||
return nil, fmt.Errorf("folder %q: %w", folder.ID, errFolderIDDuplicate)
|
||||
}
|
||||
|
||||
folder.prepare(myID, existingDevices)
|
||||
|
||||
existingFolders[folder.ID] = folder
|
||||
|
||||
for _, dev := range folder.Devices {
|
||||
sharedFolders[dev.DeviceID] = append(sharedFolders[dev.DeviceID], folder.ID)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Options.RawListenAddresses = util.UniqueTrimmedStrings(cfg.Options.RawListenAddresses)
|
||||
cfg.Options.RawGlobalAnnServers = util.UniqueTrimmedStrings(cfg.Options.RawGlobalAnnServers)
|
||||
|
||||
if cfg.Version > 0 && cfg.Version < OldestHandledVersion {
|
||||
l.Warnf("Configuration version %d is deprecated. Attempting best effort conversion, but please verify manually.", cfg.Version)
|
||||
}
|
||||
|
||||
// Upgrade configuration versions as appropriate
|
||||
migrationsMut.Lock()
|
||||
migrations.apply(cfg)
|
||||
migrationsMut.Unlock()
|
||||
|
||||
// Build a list of available devices
|
||||
existingDevices := make(map[protocol.DeviceID]bool)
|
||||
for _, device := range cfg.Devices {
|
||||
existingDevices[device.DeviceID] = true
|
||||
}
|
||||
|
||||
// Ensure that the folder list is sorted by ID
|
||||
sort.Slice(cfg.Folders, func(a, b int) bool {
|
||||
return cfg.Folders[a].ID < cfg.Folders[b].ID
|
||||
})
|
||||
return sharedFolders, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
sharedFolders := make(map[protocol.DeviceID][]string, len(cfg.Devices))
|
||||
for i := range cfg.Folders {
|
||||
cfg.Folders[i].Devices = ensureExistingDevices(cfg.Folders[i].Devices, existingDevices)
|
||||
cfg.Folders[i].Devices = ensureNoDuplicateFolderDevices(cfg.Folders[i].Devices)
|
||||
if cfg.Folders[i].Versioning.Params == nil {
|
||||
cfg.Folders[i].Versioning.Params = map[string]string{}
|
||||
}
|
||||
sort.Slice(cfg.Folders[i].Devices, func(a, b int) bool {
|
||||
return cfg.Folders[i].Devices[a].DeviceID.Compare(cfg.Folders[i].Devices[b].DeviceID) == -1
|
||||
})
|
||||
for _, dev := range cfg.Folders[i].Devices {
|
||||
sharedFolders[dev.DeviceID] = append(sharedFolders[dev.DeviceID], cfg.Folders[i].ID)
|
||||
}
|
||||
}
|
||||
|
||||
func (cfg *Configuration) prepareDevices(sharedFolders map[protocol.DeviceID][]string) {
|
||||
for i := range cfg.Devices {
|
||||
cfg.Devices[i].prepare(sharedFolders[cfg.Devices[i].DeviceID])
|
||||
}
|
||||
}
|
||||
|
||||
// Very short reconnection intervals are annoying
|
||||
if cfg.Options.ReconnectIntervalS < 5 {
|
||||
cfg.Options.ReconnectIntervalS = 5
|
||||
}
|
||||
|
||||
if cfg.GUI.APIKey == "" {
|
||||
cfg.GUI.APIKey = rand.String(32)
|
||||
}
|
||||
|
||||
func (cfg *Configuration) prepareIgnoredDevices(existingDevices map[protocol.DeviceID]bool) map[protocol.DeviceID]bool {
|
||||
// The list of ignored devices should not contain any devices that have
|
||||
// been manually added to the config.
|
||||
var newIgnoredDevices []ObservedDevice
|
||||
ignoredDevices := make(map[protocol.DeviceID]bool)
|
||||
newIgnoredDevices := cfg.IgnoredDevices[:0]
|
||||
ignoredDevices := make(map[protocol.DeviceID]bool, len(cfg.IgnoredDevices))
|
||||
for _, dev := range cfg.IgnoredDevices {
|
||||
if !existingDevices[dev.ID] {
|
||||
ignoredDevices[dev.ID] = true
|
||||
@ -362,7 +351,10 @@ func (cfg *Configuration) clean() error {
|
||||
}
|
||||
}
|
||||
cfg.IgnoredDevices = newIgnoredDevices
|
||||
return ignoredDevices
|
||||
}
|
||||
|
||||
func (cfg *Configuration) preparePendingDevices(existingDevices, ignoredDevices map[protocol.DeviceID]bool) {
|
||||
// The list of pending devices should not contain devices that were added manually, nor should it contain
|
||||
// ignored devices.
|
||||
|
||||
@ -371,7 +363,7 @@ func (cfg *Configuration) clean() error {
|
||||
return cfg.PendingDevices[i].Time.Before(cfg.PendingDevices[j].Time)
|
||||
})
|
||||
|
||||
var newPendingDevices []ObservedDevice
|
||||
newPendingDevices := cfg.PendingDevices[:0]
|
||||
nextPendingDevice:
|
||||
for _, pendingDevice := range cfg.PendingDevices {
|
||||
if !existingDevices[pendingDevice.ID] && !ignoredDevices[pendingDevice.ID] {
|
||||
@ -385,7 +377,9 @@ nextPendingDevice:
|
||||
}
|
||||
}
|
||||
cfg.PendingDevices = newPendingDevices
|
||||
}
|
||||
|
||||
func (cfg *Configuration) removeDeprecatedProtocols() {
|
||||
// Deprecated protocols are removed from the list of listeners and
|
||||
// device addresses. So far just kcp*.
|
||||
for _, prefix := range []string{"kcp"} {
|
||||
@ -395,35 +389,17 @@ nextPendingDevice:
|
||||
dev.Addresses = filterURLSchemePrefix(dev.Addresses, prefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize any empty slices
|
||||
if cfg.Folders == nil {
|
||||
cfg.Folders = []FolderConfiguration{}
|
||||
}
|
||||
if cfg.IgnoredDevices == nil {
|
||||
cfg.IgnoredDevices = []ObservedDevice{}
|
||||
}
|
||||
if cfg.PendingDevices == nil {
|
||||
cfg.PendingDevices = []ObservedDevice{}
|
||||
}
|
||||
if cfg.Options.AlwaysLocalNets == nil {
|
||||
cfg.Options.AlwaysLocalNets = []string{}
|
||||
}
|
||||
if cfg.Options.UnackedNotificationIDs == nil {
|
||||
cfg.Options.UnackedNotificationIDs = []string{}
|
||||
} else if cfg.GUI.User != "" && cfg.GUI.Password != "" {
|
||||
for i, key := range cfg.Options.UnackedNotificationIDs {
|
||||
if key == "authenticationUserAndPassword" {
|
||||
cfg.Options.UnackedNotificationIDs = append(cfg.Options.UnackedNotificationIDs[:i], cfg.Options.UnackedNotificationIDs[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if cfg.Options.FeatureFlags == nil {
|
||||
cfg.Options.FeatureFlags = []string{}
|
||||
func (cfg *Configuration) applyMigrations() {
|
||||
if cfg.Version > 0 && cfg.Version < OldestHandledVersion {
|
||||
l.Warnf("Configuration version %d is deprecated. Attempting best effort conversion, but please verify manually.", cfg.Version)
|
||||
}
|
||||
|
||||
return nil
|
||||
// Upgrade configuration versions as appropriate
|
||||
migrationsMut.Lock()
|
||||
migrations.apply(cfg)
|
||||
migrationsMut.Unlock()
|
||||
}
|
||||
|
||||
// DeviceMap returns a map of device ID to device configuration for the given configuration.
|
||||
|
@ -526,7 +526,7 @@ func TestNewSaveLoad(t *testing.T) {
|
||||
}
|
||||
|
||||
intCfg := New(device1)
|
||||
cfg := wrap(path, intCfg)
|
||||
cfg := wrap(path, intCfg, device1)
|
||||
|
||||
if exists(path) {
|
||||
t.Error(path, "exists")
|
||||
@ -646,7 +646,7 @@ func TestPullOrder(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wrapper = wrap("testdata/pullorder.xml", cfg)
|
||||
wrapper = wrap("testdata/pullorder.xml", cfg, device1)
|
||||
folders = wrapper.Folders()
|
||||
|
||||
for _, tc := range expected {
|
||||
@ -941,7 +941,8 @@ func TestIssue4219(t *testing.T) {
|
||||
]
|
||||
}`))
|
||||
|
||||
cfg, err := ReadJSON(r, protocol.LocalDeviceID)
|
||||
myID := protocol.LocalDeviceID
|
||||
cfg, err := ReadJSON(r, myID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -959,7 +960,7 @@ func TestIssue4219(t *testing.T) {
|
||||
t.Errorf("There should be three ignored folders, not %d", ignoredFolders)
|
||||
}
|
||||
|
||||
w := wrap("/tmp/cfg", cfg)
|
||||
w := wrap("/tmp/cfg", cfg, myID)
|
||||
if !w.IgnoredFolder(device2, "t1") {
|
||||
t.Error("Folder device2 t1 should be ignored")
|
||||
}
|
||||
@ -1119,12 +1120,16 @@ func TestRemoveDeviceWithEmptyID(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
cfg.clean()
|
||||
cfg.prepare(device1)
|
||||
|
||||
if len(cfg.Devices) != 0 {
|
||||
if len(cfg.Devices) != 1 {
|
||||
t.Error("Expected one device")
|
||||
} else if cfg.Devices[0].DeviceID != device1 {
|
||||
t.Error("Expected device with empty ID to be removed from config:", cfg.Devices)
|
||||
}
|
||||
if len(cfg.Folders[0].Devices) != 0 {
|
||||
if len(cfg.Folders[0].Devices) != 1 {
|
||||
t.Error("Expected one device in folder")
|
||||
} else if cfg.Folders[0].Devices[0].DeviceID != device1 {
|
||||
t.Error("Expected device with empty ID to be removed from folder")
|
||||
}
|
||||
}
|
||||
@ -1175,8 +1180,8 @@ func load(path string, myID protocol.DeviceID) (Wrapper, error) {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
func wrap(path string, cfg Configuration) Wrapper {
|
||||
return Wrap(path, cfg, events.NoopLogger)
|
||||
func wrap(path string, cfg Configuration, myID protocol.DeviceID) Wrapper {
|
||||
return Wrap(path, cfg, myID, events.NoopLogger)
|
||||
}
|
||||
|
||||
func TestInternalVersioningConfiguration(t *testing.T) {
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -43,7 +44,7 @@ func NewFolderConfiguration(myID protocol.DeviceID, id, label string, fsType fs.
|
||||
|
||||
util.SetDefaults(&f)
|
||||
|
||||
f.prepare()
|
||||
f.prepare(myID, nil)
|
||||
return f
|
||||
}
|
||||
|
||||
@ -182,7 +183,19 @@ func (f *FolderConfiguration) DeviceIDs() []protocol.DeviceID {
|
||||
return deviceIDs
|
||||
}
|
||||
|
||||
func (f *FolderConfiguration) prepare() {
|
||||
func (f *FolderConfiguration) prepare(myID protocol.DeviceID, existingDevices map[protocol.DeviceID]bool) {
|
||||
// Ensure that
|
||||
// - any loose devices are not present in the wrong places
|
||||
// - there are no duplicate devices
|
||||
// - we are part of the devices
|
||||
f.Devices = ensureExistingDevices(f.Devices, existingDevices)
|
||||
f.Devices = ensureNoDuplicateFolderDevices(f.Devices)
|
||||
f.Devices = ensureDevicePresent(f.Devices, myID)
|
||||
|
||||
sort.Slice(f.Devices, func(a, b int) bool {
|
||||
return f.Devices[a].DeviceID.Compare(f.Devices[b].DeviceID) == -1
|
||||
})
|
||||
|
||||
if f.RescanIntervalS > MaxRescanIntervalS {
|
||||
f.RescanIntervalS = MaxRescanIntervalS
|
||||
} else if f.RescanIntervalS < 0 {
|
||||
@ -194,9 +207,6 @@ func (f *FolderConfiguration) prepare() {
|
||||
f.FSWatcherDelayS = 10
|
||||
}
|
||||
|
||||
if f.Versioning.Params == nil {
|
||||
f.Versioning.Params = make(map[string]string)
|
||||
}
|
||||
if f.Versioning.CleanupIntervalS > MaxRescanIntervalS {
|
||||
f.Versioning.CleanupIntervalS = MaxRescanIntervalS
|
||||
} else if f.Versioning.CleanupIntervalS < 0 {
|
||||
|
@ -11,6 +11,8 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/rand"
|
||||
)
|
||||
|
||||
func (c GUIConfiguration) IsAuthEnabled() bool {
|
||||
@ -126,6 +128,12 @@ func (c GUIConfiguration) IsValidAPIKey(apiKey string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *GUIConfiguration) prepare() {
|
||||
if c.APIKey == "" {
|
||||
c.APIKey = rand.String(32)
|
||||
}
|
||||
}
|
||||
|
||||
func (c GUIConfiguration) Copy() GUIConfiguration {
|
||||
return c
|
||||
}
|
||||
|
@ -28,6 +28,27 @@ func (opts OptionsConfiguration) Copy() OptionsConfiguration {
|
||||
return optsCopy
|
||||
}
|
||||
|
||||
func (opts *OptionsConfiguration) prepare(guiPWIsSet bool) {
|
||||
util.FillNilSlices(opts)
|
||||
|
||||
opts.RawListenAddresses = util.UniqueTrimmedStrings(opts.RawListenAddresses)
|
||||
opts.RawGlobalAnnServers = util.UniqueTrimmedStrings(opts.RawGlobalAnnServers)
|
||||
|
||||
// Very short reconnection intervals are annoying
|
||||
if opts.ReconnectIntervalS < 5 {
|
||||
opts.ReconnectIntervalS = 5
|
||||
}
|
||||
|
||||
if guiPWIsSet && len(opts.UnackedNotificationIDs) > 0 {
|
||||
for i, key := range opts.UnackedNotificationIDs {
|
||||
if key == "authenticationUserAndPassword" {
|
||||
opts.UnackedNotificationIDs = append(opts.UnackedNotificationIDs[:i], opts.UnackedNotificationIDs[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RequiresRestartOnly returns a copy with only the attributes that require
|
||||
// restart on change.
|
||||
func (opts OptionsConfiguration) RequiresRestartOnly() OptionsConfiguration {
|
||||
|
@ -55,6 +55,7 @@ func (noopWaiter) Wait() {}
|
||||
// notifications of changes to registered Handlers
|
||||
type Wrapper interface {
|
||||
ConfigPath() string
|
||||
MyID() protocol.DeviceID
|
||||
|
||||
RawCopy() Configuration
|
||||
Replace(cfg Configuration) (Waiter, error)
|
||||
@ -97,6 +98,7 @@ type wrapper struct {
|
||||
cfg Configuration
|
||||
path string
|
||||
evLogger events.Logger
|
||||
myID protocol.DeviceID
|
||||
|
||||
waiter Waiter // Latest ongoing config change
|
||||
subs []Committer
|
||||
@ -107,11 +109,12 @@ type wrapper struct {
|
||||
|
||||
// Wrap wraps an existing Configuration structure and ties it to a file on
|
||||
// disk.
|
||||
func Wrap(path string, cfg Configuration, evLogger events.Logger) Wrapper {
|
||||
func Wrap(path string, cfg Configuration, myID protocol.DeviceID, evLogger events.Logger) Wrapper {
|
||||
w := &wrapper{
|
||||
cfg: cfg,
|
||||
path: path,
|
||||
evLogger: evLogger,
|
||||
myID: myID,
|
||||
waiter: noopWaiter{}, // Noop until first config change
|
||||
mut: sync.NewMutex(),
|
||||
}
|
||||
@ -132,13 +135,17 @@ func Load(path string, myID protocol.DeviceID, evLogger events.Logger) (Wrapper,
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return Wrap(path, cfg, evLogger), originalVersion, nil
|
||||
return Wrap(path, cfg, myID, evLogger), originalVersion, nil
|
||||
}
|
||||
|
||||
func (w *wrapper) ConfigPath() string {
|
||||
return w.path
|
||||
}
|
||||
|
||||
func (w *wrapper) MyID() protocol.DeviceID {
|
||||
return w.myID
|
||||
}
|
||||
|
||||
// Subscribe registers the given handler to be called on any future
|
||||
// configuration changes.
|
||||
func (w *wrapper) Subscribe(c Committer) {
|
||||
@ -184,7 +191,7 @@ func (w *wrapper) Replace(cfg Configuration) (Waiter, error) {
|
||||
func (w *wrapper) replaceLocked(to Configuration) (Waiter, error) {
|
||||
from := w.cfg
|
||||
|
||||
if err := to.clean(); err != nil {
|
||||
if err := to.prepare(w.myID); err != nil {
|
||||
return noopWaiter{}, err
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
)
|
||||
|
||||
func TestIsLANHost(t *testing.T) {
|
||||
@ -36,7 +37,7 @@ func TestIsLANHost(t *testing.T) {
|
||||
Options: config.OptionsConfiguration{
|
||||
AlwaysLocalNets: []string{"10.20.30.0/24"},
|
||||
},
|
||||
}, events.NoopLogger)
|
||||
}, protocol.LocalDeviceID, events.NoopLogger)
|
||||
s := &service{cfg: cfg}
|
||||
|
||||
for _, tc := range cases {
|
||||
|
@ -30,7 +30,7 @@ func init() {
|
||||
}
|
||||
|
||||
func initConfig() config.Wrapper {
|
||||
cfg := config.Wrap("/dev/null", config.New(device1), events.NoopLogger)
|
||||
cfg := config.Wrap("/dev/null", config.New(device1), device1, events.NoopLogger)
|
||||
dev1Conf = config.NewDeviceConfiguration(device1, "device1")
|
||||
dev2Conf = config.NewDeviceConfiguration(device2, "device2")
|
||||
dev3Conf = config.NewDeviceConfiguration(device3, "device3")
|
||||
|
@ -23,7 +23,7 @@ func setupCache() *manager {
|
||||
cfg.Options.LocalAnnEnabled = false
|
||||
cfg.Options.GlobalAnnEnabled = false
|
||||
|
||||
return NewManager(protocol.LocalDeviceID, config.Wrap("", cfg, events.NoopLogger), tls.Certificate{}, events.NoopLogger, nil).(*manager)
|
||||
return NewManager(protocol.LocalDeviceID, config.Wrap("", cfg, protocol.LocalDeviceID, events.NoopLogger), tls.Certificate{}, events.NoopLogger, nil).(*manager)
|
||||
}
|
||||
|
||||
func TestCacheUnique(t *testing.T) {
|
||||
|
@ -115,7 +115,7 @@ func createTmpWrapper(cfg config.Configuration) config.Wrapper {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
wrapper := config.Wrap(tmpFile.Name(), cfg, events.NoopLogger)
|
||||
wrapper := config.Wrap(tmpFile.Name(), cfg, myID, events.NoopLogger)
|
||||
tmpFile.Close()
|
||||
return wrapper
|
||||
}
|
||||
@ -331,7 +331,7 @@ func TestDeviceRename(t *testing.T) {
|
||||
DeviceID: device1,
|
||||
},
|
||||
}
|
||||
cfg := config.Wrap("testdata/tmpconfig.xml", rawCfg, events.NoopLogger)
|
||||
cfg := config.Wrap("testdata/tmpconfig.xml", rawCfg, device1, events.NoopLogger)
|
||||
|
||||
db := db.NewLowlevel(backend.OpenMemory())
|
||||
m := newModel(cfg, myID, "syncthing", "dev", db, nil)
|
||||
|
@ -64,7 +64,7 @@ func TestMappingClearAddresses(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w := config.Wrap(tmpFile.Name(), config.Configuration{}, events.NoopLogger)
|
||||
w := config.Wrap(tmpFile.Name(), config.Configuration{}, protocol.LocalDeviceID, events.NoopLogger)
|
||||
defer os.RemoveAll(tmpFile.Name())
|
||||
tmpFile.Close()
|
||||
|
||||
|
@ -37,7 +37,7 @@ func TestShortIDCheck(t *testing.T) {
|
||||
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 0, 0}},
|
||||
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 1, 1}}, // first 56 bits same, differ in the first 64 bits
|
||||
},
|
||||
}, events.NoopLogger)
|
||||
}, protocol.LocalDeviceID, events.NoopLogger)
|
||||
defer os.Remove(cfg.ConfigPath())
|
||||
|
||||
if err := checkShortIDs(cfg); err != nil {
|
||||
@ -49,7 +49,7 @@ func TestShortIDCheck(t *testing.T) {
|
||||
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 64, 0}},
|
||||
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 64, 1}}, // first 64 bits same
|
||||
},
|
||||
}, events.NoopLogger)
|
||||
}, protocol.LocalDeviceID, events.NoopLogger)
|
||||
|
||||
if err := checkShortIDs(cfg); err == nil {
|
||||
t.Error("Should have gotten an error")
|
||||
@ -76,7 +76,7 @@ func TestStartupFail(t *testing.T) {
|
||||
{DeviceID: id},
|
||||
{DeviceID: conflID},
|
||||
},
|
||||
}, events.NoopLogger)
|
||||
}, protocol.LocalDeviceID, events.NoopLogger)
|
||||
defer os.Remove(cfg.ConfigPath())
|
||||
|
||||
db := backend.OpenMemory()
|
||||
|
@ -49,12 +49,12 @@ func DefaultConfig(path string, myID protocol.DeviceID, evLogger events.Logger,
|
||||
|
||||
if noDefaultFolder {
|
||||
l.Infoln("We will skip creation of a default folder on first start")
|
||||
return config.Wrap(path, newCfg, evLogger), nil
|
||||
return config.Wrap(path, newCfg, myID, evLogger), nil
|
||||
}
|
||||
|
||||
newCfg.Folders = append(newCfg.Folders, config.NewFolderConfiguration(myID, "default", "Default Folder", fs.FilesystemTypeBasic, locations.Get(locations.DefFolder)))
|
||||
l.Infoln("Default folder created and/or linked to new config")
|
||||
return config.Wrap(path, newCfg, evLogger), nil
|
||||
return config.Wrap(path, newCfg, myID, evLogger), nil
|
||||
}
|
||||
|
||||
// LoadConfigAtStartup loads an existing config. If it doesn't yet exist, it
|
||||
|
@ -83,6 +83,10 @@ func SetDefaults(data interface{}) {
|
||||
default:
|
||||
panic(f.Type())
|
||||
}
|
||||
} else if f.CanSet() && f.Kind() == reflect.Struct && f.CanAddr() {
|
||||
if addr := f.Addr(); addr.CanInterface() {
|
||||
SetDefaults(addr.Interface())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -137,9 +141,22 @@ func UniqueTrimmedStrings(ss []string) []string {
|
||||
return us
|
||||
}
|
||||
|
||||
func FillNilExceptDeprecated(data interface{}) {
|
||||
fillNil(data, true)
|
||||
}
|
||||
|
||||
func FillNil(data interface{}) {
|
||||
fillNil(data, false)
|
||||
}
|
||||
|
||||
func fillNil(data interface{}, skipDeprecated bool) {
|
||||
s := reflect.ValueOf(data).Elem()
|
||||
t := s.Type()
|
||||
for i := 0; i < s.NumField(); i++ {
|
||||
if skipDeprecated && strings.HasPrefix(t.Field(i).Name, "Deprecated") {
|
||||
continue
|
||||
}
|
||||
|
||||
f := s.Field(i)
|
||||
|
||||
for f.Kind() == reflect.Ptr && f.IsZero() && f.CanSet() {
|
||||
@ -160,9 +177,19 @@ func FillNil(data interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
if f.Kind() == reflect.Struct && f.CanAddr() {
|
||||
if addr := f.Addr(); addr.CanInterface() {
|
||||
FillNil(addr.Interface())
|
||||
switch f.Kind() {
|
||||
case reflect.Slice:
|
||||
if f.Type().Elem().Kind() != reflect.Struct {
|
||||
continue
|
||||
}
|
||||
for i := 0; i < f.Len(); i++ {
|
||||
fillNil(f.Index(i).Addr().Interface(), skipDeprecated)
|
||||
}
|
||||
case reflect.Struct:
|
||||
if f.CanAddr() {
|
||||
if addr := f.Addr(); addr.CanInterface() {
|
||||
fillNil(addr.Interface(), skipDeprecated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/fs"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
@ -47,7 +48,7 @@ var (
|
||||
}
|
||||
defaultCfg = config.Wrap("", config.Configuration{
|
||||
Folders: []config.FolderConfiguration{defaultFolderCfg},
|
||||
}, events.NoopLogger)
|
||||
}, protocol.LocalDeviceID, events.NoopLogger)
|
||||
)
|
||||
|
||||
// Represents possibly multiple (different event types) expected paths from
|
||||
|
Loading…
Reference in New Issue
Block a user