all: Hide implementations behind interfaces for mocked testing (#5548)

* lib/model: Hide implementations behind interfaces for mocked testing

* review
This commit is contained in:
Simon Frei 2019-02-26 09:09:25 +01:00 committed by Audrius Butkevicius
parent 8a05492622
commit 722b3fce6a
30 changed files with 405 additions and 270 deletions

View File

@ -40,11 +40,9 @@ import (
"github.com/syncthing/syncthing/lib/model"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/stats"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/tlsutil"
"github.com/syncthing/syncthing/lib/upgrade"
"github.com/syncthing/syncthing/lib/versioner"
"github.com/vitrun/qart/qr"
"golang.org/x/crypto/bcrypt"
)
@ -64,15 +62,15 @@ const (
type apiService struct {
id protocol.DeviceID
cfg configIntf
cfg config.Wrapper
httpsCertFile string
httpsKeyFile string
statics *staticsServer
model modelIntf
model model.Model
eventSubs map[events.EventType]events.BufferedSubscription
eventSubsMut sync.Mutex
discoverer discover.CachingMux
connectionsService connectionsIntf
connectionsService connections.Service
fss *folderSummaryService
systemConfigMut sync.Mutex // serializes posts to /rest/system/config
stop chan struct{} // signals intentional stop
@ -86,69 +84,11 @@ type apiService struct {
systemLog logger.Recorder
}
type modelIntf interface {
GlobalDirectoryTree(folder, prefix string, levels int, dirsonly bool) map[string]interface{}
Completion(device protocol.DeviceID, folder string) model.FolderCompletion
Override(folder string)
Revert(folder string)
NeedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated)
RemoteNeedFolderFiles(device protocol.DeviceID, folder string, page, perpage int) ([]db.FileInfoTruncated, error)
LocalChangedFiles(folder string, page, perpage int) []db.FileInfoTruncated
NeedSize(folder string) db.Counts
ConnectionStats() map[string]interface{}
DeviceStatistics() map[string]stats.DeviceStatistics
FolderStatistics() map[string]stats.FolderStatistics
CurrentFolderFile(folder string, file string) (protocol.FileInfo, bool)
CurrentGlobalFile(folder string, file string) (protocol.FileInfo, bool)
ResetFolder(folder string)
Availability(folder string, file protocol.FileInfo, block protocol.BlockInfo) []model.Availability
GetIgnores(folder string) ([]string, []string, error)
GetFolderVersions(folder string) (map[string][]versioner.FileVersion, error)
RestoreFolderVersions(folder string, versions map[string]time.Time) (map[string]string, error)
SetIgnores(folder string, content []string) error
DelayScan(folder string, next time.Duration)
ScanFolder(folder string) error
ScanFolders() map[string]error
ScanFolderSubdirs(folder string, subs []string) error
BringToFront(folder, file string)
Connection(deviceID protocol.DeviceID) (connections.Connection, bool)
GlobalSize(folder string) db.Counts
LocalSize(folder string) db.Counts
ReceiveOnlyChangedSize(folder string) db.Counts
CurrentSequence(folder string) (int64, bool)
RemoteSequence(folder string) (int64, bool)
State(folder string) (string, time.Time, error)
UsageReportingStats(version int, preview bool) map[string]interface{}
FolderErrors(folder string) ([]model.FileError, error)
WatchError(folder string) error
}
type configIntf interface {
GUI() config.GUIConfiguration
LDAP() config.LDAPConfiguration
RawCopy() config.Configuration
Options() config.OptionsConfiguration
Replace(cfg config.Configuration) (config.Waiter, error)
Subscribe(c config.Committer)
Folders() map[string]config.FolderConfiguration
Devices() map[protocol.DeviceID]config.DeviceConfiguration
SetDevice(config.DeviceConfiguration) (config.Waiter, error)
SetDevices([]config.DeviceConfiguration) (config.Waiter, error)
Save() error
ListenAddresses() []string
RequiresRestart() bool
}
type connectionsIntf interface {
Status() map[string]interface{}
NATType() string
}
type rater interface {
Rate() float64
}
func newAPIService(id protocol.DeviceID, cfg configIntf, httpsCertFile, httpsKeyFile, assetDir string, m modelIntf, defaultSub, diskSub events.BufferedSubscription, discoverer discover.CachingMux, connectionsService connectionsIntf, errors, systemLog logger.Recorder, cpu rater) *apiService {
func newAPIService(id protocol.DeviceID, cfg config.Wrapper, httpsCertFile, httpsKeyFile, assetDir string, m model.Model, defaultSub, diskSub events.BufferedSubscription, discoverer discover.CachingMux, connectionsService connections.Service, errors, systemLog logger.Recorder, cpu rater) *apiService {
service := &apiService{
id: id,
cfg: cfg,
@ -719,7 +659,7 @@ func (s *apiService) getDBStatus(w http.ResponseWriter, r *http.Request) {
}
}
func folderSummary(cfg configIntf, m modelIntf, folder string) (map[string]interface{}, error) {
func folderSummary(cfg config.Wrapper, m model.Model, folder string) (map[string]interface{}, error) {
var res = make(map[string]interface{})
errors, err := m.FolderErrors(folder)

View File

@ -956,7 +956,7 @@ func setupSignalHandling() {
}()
}
func loadOrDefaultConfig() (*config.Wrapper, error) {
func loadOrDefaultConfig() (config.Wrapper, error) {
cfgFile := locations.Get(locations.ConfigFile)
cfg, err := config.Load(cfgFile, myID)
@ -967,7 +967,7 @@ func loadOrDefaultConfig() (*config.Wrapper, error) {
return cfg, err
}
func loadConfigAtStartup() (*config.Wrapper, error) {
func loadConfigAtStartup() (config.Wrapper, error) {
cfgFile := locations.Get(locations.ConfigFile)
cfg, err := config.Load(cfgFile, myID)
if os.IsNotExist(err) {
@ -996,7 +996,7 @@ func loadConfigAtStartup() (*config.Wrapper, error) {
return cfg, nil
}
func archiveAndSaveConfig(cfg *config.Wrapper) error {
func archiveAndSaveConfig(cfg config.Wrapper) error {
// Copy the existing config to an archive copy
archivePath := cfg.ConfigPath() + fmt.Sprintf(".v%d", cfg.RawCopy().OriginalVersion)
l.Infoln("Archiving a copy of old config file format at:", archivePath)
@ -1061,7 +1061,7 @@ func startAuditing(mainService *suture.Supervisor, auditFile string) {
l.Infoln("Audit log in", auditDest)
}
func setupGUI(mainService *suture.Supervisor, cfg *config.Wrapper, m *model.Model, defaultSub, diskSub events.BufferedSubscription, discoverer discover.CachingMux, connectionsService *connections.Service, errors, systemLog logger.Recorder, runtimeOptions RuntimeOptions) {
func setupGUI(mainService *suture.Supervisor, cfg config.Wrapper, m model.Model, defaultSub, diskSub events.BufferedSubscription, discoverer discover.CachingMux, connectionsService connections.Service, errors, systemLog logger.Recorder, runtimeOptions RuntimeOptions) {
guiCfg := cfg.GUI()
if !guiCfg.Enabled {
@ -1091,7 +1091,7 @@ func setupGUI(mainService *suture.Supervisor, cfg *config.Wrapper, m *model.Mode
}
}
func defaultConfig(cfgFile string) (*config.Wrapper, error) {
func defaultConfig(cfgFile string) (config.Wrapper, error) {
newCfg, err := config.NewWithFreePorts(myID)
if err != nil {
return nil, err
@ -1154,7 +1154,7 @@ func standbyMonitor() {
}
}
func autoUpgrade(cfg *config.Wrapper) {
func autoUpgrade(cfg config.Wrapper) {
timer := time.NewTimer(0)
sub := events.Default.Subscribe(events.DeviceConnected)
for {
@ -1256,7 +1256,7 @@ func cleanConfigDirectory() {
// checkShortIDs verifies that the configuration won't result in duplicate
// short ID:s; that is, that the devices in the cluster all have unique
// initial 64 bits.
func checkShortIDs(cfg *config.Wrapper) error {
func checkShortIDs(cfg config.Wrapper) error {
exists := make(map[protocol.ShortID]protocol.DeviceID)
for deviceID := range cfg.Devices() {
shortID := deviceID.Short()
@ -1278,7 +1278,7 @@ func showPaths(options RuntimeOptions) {
fmt.Printf("Default sync folder directory:\n\t%s\n\n", locations.Get(locations.DefFolder))
}
func setPauseState(cfg *config.Wrapper, paused bool) {
func setPauseState(cfg config.Wrapper, paused bool) {
raw := cfg.RawCopy()
for i := range raw.Devices {
raw.Devices[i].Paused = paused

View File

@ -44,6 +44,8 @@ func (c *mockedConfig) Replace(cfg config.Configuration) (config.Waiter, error)
func (c *mockedConfig) Subscribe(cm config.Committer) {}
func (c *mockedConfig) Unsubscribe(cm config.Committer) {}
func (c *mockedConfig) Folders() map[string]config.FolderConfiguration {
return nil
}
@ -68,6 +70,58 @@ func (c *mockedConfig) RequiresRestart() bool {
return false
}
func (c *mockedConfig) AddOrUpdatePendingDevice(device protocol.DeviceID, name, address string) {}
func (c *mockedConfig) AddOrUpdatePendingFolder(id, label string, device protocol.DeviceID) {}
func (m *mockedConfig) MyName() string {
return ""
}
func (m *mockedConfig) ConfigPath() string {
return ""
}
func (m *mockedConfig) SetGUI(gui config.GUIConfiguration) (config.Waiter, error) {
return noopWaiter{}, nil
}
func (m *mockedConfig) SetOptions(opts config.OptionsConfiguration) (config.Waiter, error) {
return noopWaiter{}, nil
}
func (m *mockedConfig) Folder(id string) (config.FolderConfiguration, bool) {
return config.FolderConfiguration{}, false
}
func (m *mockedConfig) FolderList() []config.FolderConfiguration {
return nil
}
func (m *mockedConfig) SetFolder(fld config.FolderConfiguration) (config.Waiter, error) {
return noopWaiter{}, nil
}
func (m *mockedConfig) Device(id protocol.DeviceID) (config.DeviceConfiguration, bool) {
return config.DeviceConfiguration{}, false
}
func (m *mockedConfig) RemoveDevice(id protocol.DeviceID) (config.Waiter, error) {
return noopWaiter{}, nil
}
func (m *mockedConfig) IgnoredDevice(id protocol.DeviceID) bool {
return false
}
func (m *mockedConfig) IgnoredFolder(device protocol.DeviceID, folder string) bool {
return false
}
func (m *mockedConfig) GlobalDiscoveryServers() []string {
return nil
}
type noopWaiter struct{}
func (noopWaiter) Wait() {}

View File

@ -15,3 +15,7 @@ func (m *mockedConnections) Status() map[string]interface{} {
func (m *mockedConnections) NATType() string {
return ""
}
func (m *mockedConnections) Serve() {}
func (m *mockedConnections) Stop() {}

View File

@ -7,8 +7,10 @@
package main
import (
"net"
"time"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/connections"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/model"
@ -150,3 +152,38 @@ func (m *mockedModel) WatchError(folder string) error {
func (m *mockedModel) LocalChangedFiles(folder string, page, perpage int) []db.FileInfoTruncated {
return nil
}
func (m *mockedModel) Serve() {}
func (m *mockedModel) Stop() {}
func (m *mockedModel) Index(deviceID protocol.DeviceID, folder string, files []protocol.FileInfo) {}
func (m *mockedModel) IndexUpdate(deviceID protocol.DeviceID, folder string, files []protocol.FileInfo) {
}
func (m *mockedModel) Request(deviceID protocol.DeviceID, folder, name string, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (protocol.RequestResponse, error) {
return nil, nil
}
func (m *mockedModel) ClusterConfig(deviceID protocol.DeviceID, config protocol.ClusterConfig) {}
func (m *mockedModel) Closed(conn protocol.Connection, err error) {}
func (m *mockedModel) DownloadProgress(deviceID protocol.DeviceID, folder string, updates []protocol.FileDownloadProgressUpdate) {
}
func (m *mockedModel) AddConnection(conn connections.Connection, hello protocol.HelloResult) {}
func (m *mockedModel) OnHello(protocol.DeviceID, net.Addr, protocol.HelloResult) error {
return nil
}
func (m *mockedModel) GetHello(protocol.DeviceID) protocol.HelloIntf {
return nil
}
func (m *mockedModel) AddFolder(cfg config.FolderConfiguration) {}
func (m *mockedModel) RestartFolder(from, to config.FolderConfiguration) {}
func (m *mockedModel) StartFolder(folder string) {}
func (m *mockedModel) StartDeadlockDetector(timeout time.Duration) {}

View File

@ -9,7 +9,9 @@ package main
import (
"time"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/model"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/sync"
"github.com/thejerf/suture"
@ -20,8 +22,8 @@ import (
type folderSummaryService struct {
*suture.Supervisor
cfg configIntf
model modelIntf
cfg config.Wrapper
model model.Model
stop chan struct{}
immediate chan string
@ -34,7 +36,7 @@ type folderSummaryService struct {
lastEventReqMut sync.Mutex
}
func newFolderSummaryService(cfg configIntf, m modelIntf) *folderSummaryService {
func newFolderSummaryService(cfg config.Wrapper, m model.Model) *folderSummaryService {
service := &folderSummaryService{
Supervisor: suture.New("folderSummaryService", suture.Spec{
PassThroughPanics: true,

View File

@ -37,7 +37,7 @@ const usageReportVersion = 3
// reportData returns the data to be sent in a usage report. It's used in
// various places, so not part of the usageReportingManager object.
func reportData(cfg configIntf, m modelIntf, connectionsService connectionsIntf, version int, preview bool) map[string]interface{} {
func reportData(cfg config.Wrapper, m model.Model, connectionsService connections.Service, version int, preview bool) map[string]interface{} {
opts := cfg.Options()
res := make(map[string]interface{})
res["urVersion"] = version
@ -323,16 +323,16 @@ func reportData(cfg configIntf, m modelIntf, connectionsService connectionsIntf,
}
type usageReportingService struct {
cfg *config.Wrapper
model *model.Model
connectionsService *connections.Service
cfg config.Wrapper
model model.Model
connectionsService connections.Service
forceRun chan struct{}
stop chan struct{}
stopped chan struct{}
stopMut sync.RWMutex
}
func newUsageReportingService(cfg *config.Wrapper, model *model.Model, connectionsService *connections.Service) *usageReportingService {
func newUsageReportingService(cfg config.Wrapper, model model.Model, connectionsService connections.Service) *usageReportingService {
svc := &usageReportingService{
cfg: cfg,
model: model,

View File

@ -93,7 +93,7 @@ func TestDeviceConfig(t *testing.T) {
t.Fatal("Unexpected file")
}
cfg := wr.cfg
cfg := wr.(*wrapper).cfg
expectedFolders := []FolderConfiguration{
{
@ -515,7 +515,7 @@ func TestNewSaveLoad(t *testing.T) {
cfg := Wrap(path, intCfg)
// To make the equality pass later
cfg.cfg.XMLName.Local = "configuration"
cfg.(*wrapper).cfg.XMLName.Local = "configuration"
if exists(path) {
t.Error(path, "exists")
@ -827,7 +827,7 @@ func TestIgnoredFolders(t *testing.T) {
// 2 for folder2, 1 for folder1, as non-existing device and device the folder is shared with is removed.
expectedIgnoredFolders := 3
for _, dev := range wrapper.cfg.Devices {
for _, dev := range wrapper.Devices() {
expectedIgnoredFolders -= len(dev.IgnoredFolders)
}
if expectedIgnoredFolders != 0 {

View File

@ -52,10 +52,48 @@ type noopWaiter struct{}
func (noopWaiter) Wait() {}
// A wrapper around a Configuration that manages loads, saves and published
// A Wrapper around a Configuration that manages loads, saves and published
// notifications of changes to registered Handlers
type Wrapper interface {
MyName() string
ConfigPath() string
type Wrapper struct {
RawCopy() Configuration
Replace(cfg Configuration) (Waiter, error)
RequiresRestart() bool
Save() error
GUI() GUIConfiguration
SetGUI(gui GUIConfiguration) (Waiter, error)
LDAP() LDAPConfiguration
Options() OptionsConfiguration
SetOptions(opts OptionsConfiguration) (Waiter, error)
Folder(id string) (FolderConfiguration, bool)
Folders() map[string]FolderConfiguration
FolderList() []FolderConfiguration
SetFolder(fld FolderConfiguration) (Waiter, error)
Device(id protocol.DeviceID) (DeviceConfiguration, bool)
Devices() map[protocol.DeviceID]DeviceConfiguration
RemoveDevice(id protocol.DeviceID) (Waiter, error)
SetDevice(DeviceConfiguration) (Waiter, error)
SetDevices([]DeviceConfiguration) (Waiter, error)
AddOrUpdatePendingDevice(device protocol.DeviceID, name, address string)
AddOrUpdatePendingFolder(id, label string, device protocol.DeviceID)
IgnoredDevice(id protocol.DeviceID) bool
IgnoredFolder(device protocol.DeviceID, folder string) bool
ListenAddresses() []string
GlobalDiscoveryServers() []string
Subscribe(c Committer)
Unsubscribe(c Committer)
}
type wrapper struct {
cfg Configuration
path string
@ -69,8 +107,8 @@ type Wrapper struct {
// Wrap wraps an existing Configuration structure and ties it to a file on
// disk.
func Wrap(path string, cfg Configuration) *Wrapper {
w := &Wrapper{
func Wrap(path string, cfg Configuration) Wrapper {
w := &wrapper{
cfg: cfg,
path: path,
mut: sync.NewMutex(),
@ -80,7 +118,7 @@ func Wrap(path string, cfg Configuration) *Wrapper {
// Load loads an existing file on disk and returns a new configuration
// wrapper.
func Load(path string, myID protocol.DeviceID) (*Wrapper, error) {
func Load(path string, myID protocol.DeviceID) (Wrapper, error) {
fd, err := os.Open(path)
if err != nil {
return nil, err
@ -95,13 +133,13 @@ func Load(path string, myID protocol.DeviceID) (*Wrapper, error) {
return Wrap(path, cfg), nil
}
func (w *Wrapper) ConfigPath() string {
func (w *wrapper) ConfigPath() string {
return w.path
}
// Subscribe registers the given handler to be called on any future
// configuration changes.
func (w *Wrapper) Subscribe(c Committer) {
func (w *wrapper) Subscribe(c Committer) {
w.mut.Lock()
w.subs = append(w.subs, c)
w.mut.Unlock()
@ -109,7 +147,7 @@ func (w *Wrapper) Subscribe(c Committer) {
// Unsubscribe de-registers the given handler from any future calls to
// configuration changes
func (w *Wrapper) Unsubscribe(c Committer) {
func (w *wrapper) Unsubscribe(c Committer) {
w.mut.Lock()
for i := range w.subs {
if w.subs[i] == c {
@ -123,20 +161,20 @@ func (w *Wrapper) Unsubscribe(c Committer) {
}
// RawCopy returns a copy of the currently wrapped Configuration object.
func (w *Wrapper) RawCopy() Configuration {
func (w *wrapper) RawCopy() Configuration {
w.mut.Lock()
defer w.mut.Unlock()
return w.cfg.Copy()
}
// Replace swaps the current configuration object for the given one.
func (w *Wrapper) Replace(cfg Configuration) (Waiter, error) {
func (w *wrapper) Replace(cfg Configuration) (Waiter, error) {
w.mut.Lock()
defer w.mut.Unlock()
return w.replaceLocked(cfg.Copy())
}
func (w *Wrapper) replaceLocked(to Configuration) (Waiter, error) {
func (w *wrapper) replaceLocked(to Configuration) (Waiter, error) {
from := w.cfg
if err := to.clean(); err != nil {
@ -158,7 +196,7 @@ func (w *Wrapper) replaceLocked(to Configuration) (Waiter, error) {
return w.notifyListeners(from.Copy(), to.Copy()), nil
}
func (w *Wrapper) notifyListeners(from, to Configuration) Waiter {
func (w *wrapper) notifyListeners(from, to Configuration) Waiter {
wg := sync.NewWaitGroup()
wg.Add(len(w.subs))
for _, sub := range w.subs {
@ -170,7 +208,7 @@ func (w *Wrapper) notifyListeners(from, to Configuration) Waiter {
return wg
}
func (w *Wrapper) notifyListener(sub Committer, from, to Configuration) {
func (w *wrapper) notifyListener(sub Committer, from, to Configuration) {
l.Debugln(sub, "committing configuration")
if !sub.CommitConfiguration(from, to) {
l.Debugln(sub, "requires restart")
@ -179,7 +217,7 @@ func (w *Wrapper) notifyListener(sub Committer, from, to Configuration) {
}
// Devices returns a map of devices.
func (w *Wrapper) Devices() map[protocol.DeviceID]DeviceConfiguration {
func (w *wrapper) Devices() map[protocol.DeviceID]DeviceConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
if w.deviceMap == nil {
@ -193,7 +231,7 @@ func (w *Wrapper) Devices() map[protocol.DeviceID]DeviceConfiguration {
// SetDevices adds new devices to the configuration, or overwrites existing
// devices with the same ID.
func (w *Wrapper) SetDevices(devs []DeviceConfiguration) (Waiter, error) {
func (w *wrapper) SetDevices(devs []DeviceConfiguration) (Waiter, error) {
w.mut.Lock()
defer w.mut.Unlock()
@ -218,12 +256,12 @@ func (w *Wrapper) SetDevices(devs []DeviceConfiguration) (Waiter, error) {
// SetDevice adds a new device to the configuration, or overwrites an existing
// device with the same ID.
func (w *Wrapper) SetDevice(dev DeviceConfiguration) (Waiter, error) {
func (w *wrapper) SetDevice(dev DeviceConfiguration) (Waiter, error) {
return w.SetDevices([]DeviceConfiguration{dev})
}
// RemoveDevice removes the device from the configuration
func (w *Wrapper) RemoveDevice(id protocol.DeviceID) (Waiter, error) {
func (w *wrapper) RemoveDevice(id protocol.DeviceID) (Waiter, error) {
w.mut.Lock()
defer w.mut.Unlock()
@ -240,7 +278,7 @@ func (w *Wrapper) RemoveDevice(id protocol.DeviceID) (Waiter, error) {
// Folders returns a map of folders. Folder structures should not be changed,
// other than for the purpose of updating via SetFolder().
func (w *Wrapper) Folders() map[string]FolderConfiguration {
func (w *wrapper) Folders() map[string]FolderConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
if w.folderMap == nil {
@ -253,7 +291,7 @@ func (w *Wrapper) Folders() map[string]FolderConfiguration {
}
// FolderList returns a slice of folders.
func (w *Wrapper) FolderList() []FolderConfiguration {
func (w *wrapper) FolderList() []FolderConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
return w.cfg.Copy().Folders
@ -261,7 +299,7 @@ func (w *Wrapper) FolderList() []FolderConfiguration {
// 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) {
func (w *wrapper) SetFolder(fld FolderConfiguration) (Waiter, error) {
w.mut.Lock()
defer w.mut.Unlock()
@ -280,14 +318,14 @@ func (w *Wrapper) SetFolder(fld FolderConfiguration) (Waiter, error) {
}
// Options returns the current options configuration object.
func (w *Wrapper) Options() OptionsConfiguration {
func (w *wrapper) Options() OptionsConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
return w.cfg.Options.Copy()
}
// SetOptions replaces the current options configuration object.
func (w *Wrapper) SetOptions(opts OptionsConfiguration) (Waiter, error) {
func (w *wrapper) SetOptions(opts OptionsConfiguration) (Waiter, error) {
w.mut.Lock()
defer w.mut.Unlock()
newCfg := w.cfg.Copy()
@ -295,21 +333,21 @@ func (w *Wrapper) SetOptions(opts OptionsConfiguration) (Waiter, error) {
return w.replaceLocked(newCfg)
}
func (w *Wrapper) LDAP() LDAPConfiguration {
func (w *wrapper) LDAP() LDAPConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
return w.cfg.LDAP.Copy()
}
// GUI returns the current GUI configuration object.
func (w *Wrapper) GUI() GUIConfiguration {
func (w *wrapper) GUI() GUIConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
return w.cfg.GUI.Copy()
}
// SetGUI replaces the current GUI configuration object.
func (w *Wrapper) SetGUI(gui GUIConfiguration) (Waiter, error) {
func (w *wrapper) SetGUI(gui GUIConfiguration) (Waiter, error) {
w.mut.Lock()
defer w.mut.Unlock()
newCfg := w.cfg.Copy()
@ -319,7 +357,7 @@ func (w *Wrapper) SetGUI(gui GUIConfiguration) (Waiter, error) {
// IgnoredDevice returns whether or not connection attempts from the given
// device should be silently ignored.
func (w *Wrapper) IgnoredDevice(id protocol.DeviceID) bool {
func (w *wrapper) IgnoredDevice(id protocol.DeviceID) bool {
w.mut.Lock()
defer w.mut.Unlock()
for _, device := range w.cfg.IgnoredDevices {
@ -332,7 +370,7 @@ func (w *Wrapper) IgnoredDevice(id protocol.DeviceID) bool {
// IgnoredFolder returns whether or not share attempts for the given
// folder should be silently ignored.
func (w *Wrapper) IgnoredFolder(device protocol.DeviceID, folder string) bool {
func (w *wrapper) IgnoredFolder(device protocol.DeviceID, folder string) bool {
dev, ok := w.Device(device)
if !ok {
return false
@ -341,7 +379,7 @@ func (w *Wrapper) IgnoredFolder(device protocol.DeviceID, folder string) bool {
}
// Device returns the configuration for the given device and an "ok" bool.
func (w *Wrapper) Device(id protocol.DeviceID) (DeviceConfiguration, bool) {
func (w *wrapper) Device(id protocol.DeviceID) (DeviceConfiguration, bool) {
w.mut.Lock()
defer w.mut.Unlock()
for _, device := range w.cfg.Devices {
@ -353,7 +391,7 @@ func (w *Wrapper) Device(id protocol.DeviceID) (DeviceConfiguration, bool) {
}
// Folder returns the configuration for the given folder and an "ok" bool.
func (w *Wrapper) Folder(id string) (FolderConfiguration, bool) {
func (w *wrapper) Folder(id string) (FolderConfiguration, bool) {
w.mut.Lock()
defer w.mut.Unlock()
for _, folder := range w.cfg.Folders {
@ -365,7 +403,7 @@ func (w *Wrapper) Folder(id string) (FolderConfiguration, bool) {
}
// Save writes the configuration to disk, and generates a ConfigSaved event.
func (w *Wrapper) Save() error {
func (w *wrapper) Save() error {
w.mut.Lock()
defer w.mut.Unlock()
@ -390,7 +428,7 @@ func (w *Wrapper) Save() error {
return nil
}
func (w *Wrapper) GlobalDiscoveryServers() []string {
func (w *wrapper) GlobalDiscoveryServers() []string {
var servers []string
for _, srv := range w.Options().GlobalAnnServers {
switch srv {
@ -407,7 +445,7 @@ func (w *Wrapper) GlobalDiscoveryServers() []string {
return util.UniqueStrings(servers)
}
func (w *Wrapper) ListenAddresses() []string {
func (w *wrapper) ListenAddresses() []string {
var addresses []string
for _, addr := range w.Options().ListenAddresses {
switch addr {
@ -420,15 +458,15 @@ func (w *Wrapper) ListenAddresses() []string {
return util.UniqueStrings(addresses)
}
func (w *Wrapper) RequiresRestart() bool {
func (w *wrapper) RequiresRestart() bool {
return atomic.LoadUint32(&w.requiresRestart) != 0
}
func (w *Wrapper) setRequiresRestart() {
func (w *wrapper) setRequiresRestart() {
atomic.StoreUint32(&w.requiresRestart, 1)
}
func (w *Wrapper) MyName() string {
func (w *wrapper) MyName() string {
w.mut.Lock()
myID := w.cfg.MyID
w.mut.Unlock()
@ -436,7 +474,7 @@ func (w *Wrapper) MyName() string {
return cfg.Name
}
func (w *Wrapper) AddOrUpdatePendingDevice(device protocol.DeviceID, name, address string) {
func (w *wrapper) AddOrUpdatePendingDevice(device protocol.DeviceID, name, address string) {
defer w.Save()
w.mut.Lock()
@ -459,7 +497,7 @@ func (w *Wrapper) AddOrUpdatePendingDevice(device protocol.DeviceID, name, addre
})
}
func (w *Wrapper) AddOrUpdatePendingFolder(id, label string, device protocol.DeviceID) {
func (w *wrapper) AddOrUpdatePendingFolder(id, label string, device protocol.DeviceID) {
defer w.Save()
w.mut.Lock()

View File

@ -36,7 +36,7 @@ func TestIsLANHost(t *testing.T) {
AlwaysLocalNets: []string{"10.20.30.0/24"},
},
})
s := &Service{cfg: cfg}
s := &service{cfg: cfg}
for _, tc := range cases {
res := s.isLANHost(tc.addr)

View File

@ -36,7 +36,7 @@ type waiter interface {
const limiterBurstSize = 4 * 128 << 10
func newLimiter(cfg *config.Wrapper) *limiter {
func newLimiter(cfg config.Wrapper) *limiter {
l := &limiter{
write: rate.NewLimiter(rate.Inf, limiterBurstSize),
read: rate.NewLimiter(rate.Inf, limiterBurstSize),

View File

@ -24,7 +24,7 @@ func init() {
device4, _ = protocol.DeviceIDFromString("P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2")
}
func initConfig() *config.Wrapper {
func initConfig() config.Wrapper {
cfg := config.Wrap("/dev/null", config.New(device1))
dev1Conf = config.NewDeviceConfiguration(device1, "device1")
dev2Conf = config.NewDeviceConfiguration(device2, "device2")

View File

@ -22,7 +22,7 @@ func init() {
}
type relayDialer struct {
cfg *config.Wrapper
cfg config.Wrapper
tlsCfg *tls.Config
}
@ -70,7 +70,7 @@ func (d *relayDialer) RedialFrequency() time.Duration {
type relayDialerFactory struct{}
func (relayDialerFactory) New(cfg *config.Wrapper, tlsCfg *tls.Config) genericDialer {
func (relayDialerFactory) New(cfg config.Wrapper, tlsCfg *tls.Config) genericDialer {
return &relayDialer{
cfg: cfg,
tlsCfg: tlsCfg,

View File

@ -29,7 +29,7 @@ type relayListener struct {
onAddressesChangedNotifier
uri *url.URL
cfg *config.Wrapper
cfg config.Wrapper
tlsCfg *tls.Config
conns chan internalConn
factory listenerFactory
@ -180,7 +180,7 @@ func (t *relayListener) NATType() string {
type relayListenerFactory struct{}
func (f *relayListenerFactory) New(uri *url.URL, cfg *config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
func (f *relayListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
return &relayListener{
uri: uri,
cfg: cfg,

View File

@ -77,9 +77,15 @@ var tlsCipherSuiteNames = map[uint16]string{
// Service listens and dials all configured unconnected devices, via supported
// dialers. Successful connections are handed to the model.
type Service struct {
type Service interface {
suture.Service
Status() map[string]interface{}
NATType() string
}
type service struct {
*suture.Supervisor
cfg *config.Wrapper
cfg config.Wrapper
myID protocol.DeviceID
model Model
tlsCfg *tls.Config
@ -97,10 +103,10 @@ type Service struct {
listenerSupervisor *suture.Supervisor
}
func NewService(cfg *config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *tls.Config, discoverer discover.Finder,
bepProtocolName string, tlsDefaultCommonName string) *Service {
func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *tls.Config, discoverer discover.Finder,
bepProtocolName string, tlsDefaultCommonName string) *service {
service := &Service{
service := &service{
Supervisor: suture.New("connections.Service", suture.Spec{
Log: func(line string) {
l.Infoln(line)
@ -156,7 +162,7 @@ func NewService(cfg *config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *
return service
}
func (s *Service) handle() {
func (s *service) handle() {
next:
for c := range s.conns {
cs := c.ConnectionState()
@ -282,7 +288,7 @@ next:
}
}
func (s *Service) connect() {
func (s *service) connect() {
nextDial := make(map[string]time.Time)
// Used as delay for the first few connection attempts, increases
@ -433,7 +439,7 @@ func (s *Service) connect() {
}
}
func (s *Service) isLANHost(host string) bool {
func (s *service) isLANHost(host string) bool {
// Probably we are called with an ip:port combo which we can resolve as
// a TCP address.
if addr, err := net.ResolveTCPAddr("tcp", host); err == nil {
@ -447,7 +453,7 @@ func (s *Service) isLANHost(host string) bool {
return false
}
func (s *Service) isLAN(addr net.Addr) bool {
func (s *service) isLAN(addr net.Addr) bool {
var ip net.IP
switch addr := addr.(type) {
@ -488,7 +494,7 @@ func (s *Service) isLAN(addr net.Addr) bool {
return false
}
func (s *Service) createListener(factory listenerFactory, uri *url.URL) bool {
func (s *service) createListener(factory listenerFactory, uri *url.URL) bool {
// must be called with listenerMut held
l.Debugln("Starting listener", uri)
@ -500,7 +506,7 @@ func (s *Service) createListener(factory listenerFactory, uri *url.URL) bool {
return true
}
func (s *Service) logListenAddressesChangedEvent(l genericListener) {
func (s *service) logListenAddressesChangedEvent(l genericListener) {
events.Default.Log(events.ListenAddressesChanged, map[string]interface{}{
"address": l.URI(),
"lan": l.LANAddresses(),
@ -508,11 +514,11 @@ func (s *Service) logListenAddressesChangedEvent(l genericListener) {
})
}
func (s *Service) VerifyConfiguration(from, to config.Configuration) error {
func (s *service) VerifyConfiguration(from, to config.Configuration) error {
return nil
}
func (s *Service) CommitConfiguration(from, to config.Configuration) bool {
func (s *service) CommitConfiguration(from, to config.Configuration) bool {
newDevices := make(map[protocol.DeviceID]bool, len(to.Devices))
for _, dev := range to.Devices {
newDevices[dev.DeviceID] = true
@ -589,7 +595,7 @@ func (s *Service) CommitConfiguration(from, to config.Configuration) bool {
return true
}
func (s *Service) AllAddresses() []string {
func (s *service) AllAddresses() []string {
s.listenersMut.RLock()
var addrs []string
for _, listener := range s.listeners {
@ -604,7 +610,7 @@ func (s *Service) AllAddresses() []string {
return util.UniqueStrings(addrs)
}
func (s *Service) ExternalAddresses() []string {
func (s *service) ExternalAddresses() []string {
s.listenersMut.RLock()
var addrs []string
for _, listener := range s.listeners {
@ -616,7 +622,7 @@ func (s *Service) ExternalAddresses() []string {
return util.UniqueStrings(addrs)
}
func (s *Service) Status() map[string]interface{} {
func (s *service) Status() map[string]interface{} {
s.listenersMut.RLock()
result := make(map[string]interface{})
for addr, listener := range s.listeners {
@ -636,7 +642,7 @@ func (s *Service) Status() map[string]interface{} {
return result
}
func (s *Service) NATType() string {
func (s *service) NATType() string {
s.listenersMut.RLock()
defer s.listenersMut.RUnlock()
for _, listener := range s.listeners {

View File

@ -122,7 +122,7 @@ func (c internalConn) String() string {
}
type dialerFactory interface {
New(*config.Wrapper, *tls.Config) genericDialer
New(config.Wrapper, *tls.Config) genericDialer
Priority() int
AlwaysWAN() bool
Valid(config.Configuration) error
@ -135,7 +135,7 @@ type genericDialer interface {
}
type listenerFactory interface {
New(*url.URL, *config.Wrapper, *tls.Config, chan internalConn, *nat.Service) genericListener
New(*url.URL, config.Wrapper, *tls.Config, chan internalConn, *nat.Service) genericListener
Valid(config.Configuration) error
}

View File

@ -24,7 +24,7 @@ func init() {
}
type tcpDialer struct {
cfg *config.Wrapper
cfg config.Wrapper
tlsCfg *tls.Config
}
@ -62,7 +62,7 @@ func (d *tcpDialer) RedialFrequency() time.Duration {
type tcpDialerFactory struct{}
func (tcpDialerFactory) New(cfg *config.Wrapper, tlsCfg *tls.Config) genericDialer {
func (tcpDialerFactory) New(cfg config.Wrapper, tlsCfg *tls.Config) genericDialer {
return &tcpDialer{
cfg: cfg,
tlsCfg: tlsCfg,

View File

@ -29,7 +29,7 @@ type tcpListener struct {
onAddressesChangedNotifier
uri *url.URL
cfg *config.Wrapper
cfg config.Wrapper
tlsCfg *tls.Config
stop chan struct{}
conns chan internalConn
@ -195,7 +195,7 @@ func (t *tcpListener) NATType() string {
type tcpListenerFactory struct{}
func (f *tcpListenerFactory) New(uri *url.URL, cfg *config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
func (f *tcpListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
return &tcpListener{
uri: fixupPort(uri, config.DefaultTCPPort),
cfg: cfg,

View File

@ -39,7 +39,7 @@ type folder struct {
config.FolderConfiguration
localFlags uint32
model *Model
model *model
shortID protocol.ShortID
ctx context.Context
cancel context.CancelFunc
@ -73,7 +73,7 @@ type puller interface {
pull() bool // true when successfull and should not be retried
}
func newFolder(model *Model, cfg config.FolderConfiguration) folder {
func newFolder(model *model, cfg config.FolderConfiguration) folder {
ctx, cancel := context.WithCancel(context.Background())
return folder{

View File

@ -56,7 +56,7 @@ type receiveOnlyFolder struct {
*sendReceiveFolder
}
func newReceiveOnlyFolder(model *Model, cfg config.FolderConfiguration, ver versioner.Versioner, fs fs.Filesystem) service {
func newReceiveOnlyFolder(model *model, cfg config.FolderConfiguration, ver versioner.Versioner, fs fs.Filesystem) service {
sr := newSendReceiveFolder(model, cfg, ver, fs).(*sendReceiveFolder)
sr.localFlags = protocol.FlagLocalReceiveOnly // gets propagated to the scanner, and set on locally changed files
return &receiveOnlyFolder{sr}

View File

@ -336,7 +336,7 @@ func setupKnownFiles(t *testing.T, data []byte) []protocol.FileInfo {
return knownFiles
}
func setupROFolder() *Model {
func setupROFolder() *model {
fcfg := config.NewFolderConfiguration(myID, "ro", "receive only test", fs.FilesystemTypeBasic, "_recvonly")
fcfg.Type = config.FolderTypeReceiveOnly
fcfg.Devices = []config.FolderDeviceConfiguration{{DeviceID: device1}}
@ -349,7 +349,7 @@ func setupROFolder() *Model {
wrp := createTmpWrapper(cfg)
db := db.OpenMemory()
m := NewModel(wrp, myID, "syncthing", "dev", db, nil)
m := newModel(wrp, myID, "syncthing", "dev", db, nil)
m.ServeBackground()
m.AddFolder(fcfg)

View File

@ -22,7 +22,7 @@ type sendOnlyFolder struct {
folder
}
func newSendOnlyFolder(model *Model, cfg config.FolderConfiguration, _ versioner.Versioner, _ fs.Filesystem) service {
func newSendOnlyFolder(model *model, cfg config.FolderConfiguration, _ versioner.Versioner, _ fs.Filesystem) service {
f := &sendOnlyFolder{
folder: newFolder(model, cfg),
}

View File

@ -104,7 +104,7 @@ type sendReceiveFolder struct {
pullErrorsMut sync.Mutex
}
func newSendReceiveFolder(model *Model, cfg config.FolderConfiguration, ver versioner.Versioner, fs fs.Filesystem) service {
func newSendReceiveFolder(model *model, cfg config.FolderConfiguration, ver versioner.Versioner, fs fs.Filesystem) service {
f := &sendReceiveFolder{
folder: newFolder(model, cfg),
fs: fs,

View File

@ -75,9 +75,9 @@ func setUpFile(filename string, blockNumbers []int) protocol.FileInfo {
}
}
func setupSendReceiveFolder(files ...protocol.FileInfo) (*Model, *sendReceiveFolder, string) {
func setupSendReceiveFolder(files ...protocol.FileInfo) (*model, *sendReceiveFolder, string) {
w := createTmpWrapper(defaultCfg)
model := NewModel(w, myID, "syncthing", "dev", db.OpenMemory(), nil)
model := newModel(w, myID, "syncthing", "dev", db.OpenMemory(), nil)
fcfg, tmpDir := testFolderConfigTmp()
model.AddFolder(fcfg)

View File

@ -76,10 +76,60 @@ type Availability struct {
FromTemporary bool `json:"fromTemporary"`
}
type Model struct {
type Model interface {
suture.Service
connections.Model
AddFolder(cfg config.FolderConfiguration)
RestartFolder(from, to config.FolderConfiguration)
StartFolder(folder string)
ResetFolder(folder string)
DelayScan(folder string, next time.Duration)
ScanFolder(folder string) error
ScanFolders() map[string]error
ScanFolderSubdirs(folder string, subs []string) error
State(folder string) (string, time.Time, error)
FolderErrors(folder string) ([]FileError, error)
WatchError(folder string) error
Override(folder string)
Revert(folder string)
BringToFront(folder, file string)
GetIgnores(folder string) ([]string, []string, error)
SetIgnores(folder string, content []string) error
GetFolderVersions(folder string) (map[string][]versioner.FileVersion, error)
RestoreFolderVersions(folder string, versions map[string]time.Time) (map[string]string, error)
LocalChangedFiles(folder string, page, perpage int) []db.FileInfoTruncated
NeedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated)
RemoteNeedFolderFiles(device protocol.DeviceID, folder string, page, perpage int) ([]db.FileInfoTruncated, error)
CurrentFolderFile(folder string, file string) (protocol.FileInfo, bool)
CurrentGlobalFile(folder string, file string) (protocol.FileInfo, bool)
Availability(folder string, file protocol.FileInfo, block protocol.BlockInfo) []Availability
GlobalSize(folder string) db.Counts
LocalSize(folder string) db.Counts
NeedSize(folder string) db.Counts
ReceiveOnlyChangedSize(folder string) db.Counts
CurrentSequence(folder string) (int64, bool)
RemoteSequence(folder string) (int64, bool)
Completion(device protocol.DeviceID, folder string) FolderCompletion
ConnectionStats() map[string]interface{}
DeviceStatistics() map[string]stats.DeviceStatistics
FolderStatistics() map[string]stats.FolderStatistics
UsageReportingStats(version int, preview bool) map[string]interface{}
StartDeadlockDetector(timeout time.Duration)
GlobalDirectoryTree(folder, prefix string, levels int, dirsonly bool) map[string]interface{}
}
type model struct {
*suture.Supervisor
cfg *config.Wrapper
cfg config.Wrapper
db *db.Lowlevel
finder *db.BlockFinder
progressEmitter *ProgressEmitter
@ -112,7 +162,7 @@ type Model struct {
foldersRunning int32 // for testing only
}
type folderFactory func(*Model, config.FolderConfiguration, versioner.Versioner, fs.Filesystem) service
type folderFactory func(*model, config.FolderConfiguration, versioner.Versioner, fs.Filesystem) service
var (
folderFactories = make(map[config.FolderType]folderFactory)
@ -134,8 +184,8 @@ var (
// NewModel creates and starts a new model. The model starts in read-only mode,
// where it sends index information to connected peers and responds to requests
// for file data without altering the local folder in any way.
func NewModel(cfg *config.Wrapper, id protocol.DeviceID, clientName, clientVersion string, ldb *db.Lowlevel, protectedFiles []string) *Model {
m := &Model{
func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersion string, ldb *db.Lowlevel, protectedFiles []string) Model {
m := &model{
Supervisor: suture.New("model", suture.Spec{
Log: func(line string) {
l.Debugln(line)
@ -180,7 +230,7 @@ func NewModel(cfg *config.Wrapper, id protocol.DeviceID, clientName, clientVersi
// StartDeadlockDetector starts a deadlock detector on the models locks which
// causes panics in case the locks cannot be acquired in the given timeout
// period.
func (m *Model) StartDeadlockDetector(timeout time.Duration) {
func (m *model) StartDeadlockDetector(timeout time.Duration) {
l.Infof("Starting deadlock detector with %v timeout", timeout)
detector := newDeadlockDetector(timeout)
detector.Watch("fmut", m.fmut)
@ -188,7 +238,7 @@ func (m *Model) StartDeadlockDetector(timeout time.Duration) {
}
// StartFolder constructs the folder service and starts it.
func (m *Model) StartFolder(folder string) {
func (m *model) StartFolder(folder string) {
m.fmut.Lock()
m.pmut.Lock()
folderType := m.startFolderLocked(folder)
@ -199,7 +249,7 @@ func (m *Model) StartFolder(folder string) {
l.Infof("Ready to synchronize %s (%s)", folderCfg.Description(), folderType)
}
func (m *Model) startFolderLocked(folder string) config.FolderType {
func (m *model) startFolderLocked(folder string) config.FolderType {
if err := m.checkFolderRunningLocked(folder); err == errFolderMissing {
panic("cannot start nonexistent folder " + folder)
} else if err == nil {
@ -274,7 +324,7 @@ func (m *Model) startFolderLocked(folder string) config.FolderType {
return cfg.Type
}
func (m *Model) warnAboutOverwritingProtectedFiles(folder string) {
func (m *model) warnAboutOverwritingProtectedFiles(folder string) {
if m.folderCfgs[folder].Type == config.FolderTypeSendOnly {
return
}
@ -308,7 +358,7 @@ func (m *Model) warnAboutOverwritingProtectedFiles(folder string) {
}
}
func (m *Model) AddFolder(cfg config.FolderConfiguration) {
func (m *model) AddFolder(cfg config.FolderConfiguration) {
if len(cfg.ID) == 0 {
panic("cannot add empty folder id")
}
@ -322,7 +372,7 @@ func (m *Model) AddFolder(cfg config.FolderConfiguration) {
m.fmut.Unlock()
}
func (m *Model) addFolderLocked(cfg config.FolderConfiguration) {
func (m *model) addFolderLocked(cfg config.FolderConfiguration) {
m.folderCfgs[cfg.ID] = cfg
folderFs := cfg.Filesystem()
m.folderFiles[cfg.ID] = db.NewFileSet(cfg.ID, folderFs, m.db)
@ -334,7 +384,7 @@ func (m *Model) addFolderLocked(cfg config.FolderConfiguration) {
m.folderIgnores[cfg.ID] = ignores
}
func (m *Model) RemoveFolder(cfg config.FolderConfiguration) {
func (m *model) RemoveFolder(cfg config.FolderConfiguration) {
m.fmut.Lock()
m.pmut.Lock()
// Delete syncthing specific files
@ -348,7 +398,7 @@ func (m *Model) RemoveFolder(cfg config.FolderConfiguration) {
m.fmut.Unlock()
}
func (m *Model) tearDownFolderLocked(cfg config.FolderConfiguration, err error) {
func (m *model) tearDownFolderLocked(cfg config.FolderConfiguration, err error) {
// Close connections to affected devices
// Must happen before stopping the folder service to abort ongoing
// transmissions and thus allow timely service termination.
@ -376,7 +426,7 @@ func (m *Model) tearDownFolderLocked(cfg config.FolderConfiguration, err error)
delete(m.folderStatRefs, cfg.ID)
}
func (m *Model) RestartFolder(from, to config.FolderConfiguration) {
func (m *model) RestartFolder(from, to config.FolderConfiguration) {
if len(to.ID) == 0 {
panic("bug: cannot restart empty folder ID")
}
@ -421,7 +471,7 @@ func (m *Model) RestartFolder(from, to config.FolderConfiguration) {
l.Infof("%v folder %v (%v)", infoMsg, to.Description(), to.Type)
}
func (m *Model) UsageReportingStats(version int, preview bool) map[string]interface{} {
func (m *model) UsageReportingStats(version int, preview bool) map[string]interface{} {
stats := make(map[string]interface{})
if version >= 3 {
// Block stats
@ -540,7 +590,7 @@ func (info ConnectionInfo) MarshalJSON() ([]byte, error) {
}
// ConnectionStats returns a map with connection statistics for each device.
func (m *Model) ConnectionStats() map[string]interface{} {
func (m *model) ConnectionStats() map[string]interface{} {
m.fmut.RLock()
m.pmut.RLock()
@ -587,7 +637,7 @@ func (m *Model) ConnectionStats() map[string]interface{} {
}
// DeviceStatistics returns statistics about each device
func (m *Model) DeviceStatistics() map[string]stats.DeviceStatistics {
func (m *model) DeviceStatistics() map[string]stats.DeviceStatistics {
res := make(map[string]stats.DeviceStatistics)
for id := range m.cfg.Devices() {
res[id.String()] = m.deviceStatRef(id).GetStatistics()
@ -596,7 +646,7 @@ func (m *Model) DeviceStatistics() map[string]stats.DeviceStatistics {
}
// FolderStatistics returns statistics about each folder
func (m *Model) FolderStatistics() map[string]stats.FolderStatistics {
func (m *model) FolderStatistics() map[string]stats.FolderStatistics {
res := make(map[string]stats.FolderStatistics)
for id := range m.cfg.Folders() {
res[id] = m.folderStatRef(id).GetStatistics()
@ -614,7 +664,7 @@ type FolderCompletion struct {
// Completion returns the completion status, in percent, for the given device
// and folder.
func (m *Model) Completion(device protocol.DeviceID, folder string) FolderCompletion {
func (m *model) Completion(device protocol.DeviceID, folder string) FolderCompletion {
m.fmut.RLock()
rf, ok := m.folderFiles[folder]
m.fmut.RUnlock()
@ -696,7 +746,7 @@ func addSizeOfFile(s *db.Counts, f db.FileIntf) {
// GlobalSize returns the number of files, deleted files and total bytes for all
// files in the global model.
func (m *Model) GlobalSize(folder string) db.Counts {
func (m *model) GlobalSize(folder string) db.Counts {
m.fmut.RLock()
defer m.fmut.RUnlock()
if rf, ok := m.folderFiles[folder]; ok {
@ -707,7 +757,7 @@ func (m *Model) GlobalSize(folder string) db.Counts {
// LocalSize returns the number of files, deleted files and total bytes for all
// files in the local folder.
func (m *Model) LocalSize(folder string) db.Counts {
func (m *model) LocalSize(folder string) db.Counts {
m.fmut.RLock()
defer m.fmut.RUnlock()
if rf, ok := m.folderFiles[folder]; ok {
@ -719,7 +769,7 @@ func (m *Model) LocalSize(folder string) db.Counts {
// ReceiveOnlyChangedSize returns the number of files, deleted files and
// total bytes for all files that have changed locally in a receieve only
// folder.
func (m *Model) ReceiveOnlyChangedSize(folder string) db.Counts {
func (m *model) ReceiveOnlyChangedSize(folder string) db.Counts {
m.fmut.RLock()
defer m.fmut.RUnlock()
if rf, ok := m.folderFiles[folder]; ok {
@ -729,7 +779,7 @@ func (m *Model) ReceiveOnlyChangedSize(folder string) db.Counts {
}
// NeedSize returns the number and total size of currently needed files.
func (m *Model) NeedSize(folder string) db.Counts {
func (m *model) NeedSize(folder string) db.Counts {
m.fmut.RLock()
defer m.fmut.RUnlock()
@ -753,7 +803,7 @@ func (m *Model) NeedSize(folder string) db.Counts {
// NeedFolderFiles returns paginated list of currently needed files in
// progress, queued, and to be queued on next puller iteration, as well as the
// total number of files currently needed.
func (m *Model) NeedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated) {
func (m *model) NeedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated) {
m.fmut.RLock()
defer m.fmut.RUnlock()
@ -820,7 +870,7 @@ func (m *Model) NeedFolderFiles(folder string, page, perpage int) ([]db.FileInfo
// LocalChangedFiles returns a paginated list of currently needed files in
// progress, queued, and to be queued on next puller iteration, as well as the
// total number of files currently needed.
func (m *Model) LocalChangedFiles(folder string, page, perpage int) []db.FileInfoTruncated {
func (m *model) LocalChangedFiles(folder string, page, perpage int) []db.FileInfoTruncated {
m.fmut.RLock()
defer m.fmut.RUnlock()
@ -861,7 +911,7 @@ func (m *Model) LocalChangedFiles(folder string, page, perpage int) []db.FileInf
// RemoteNeedFolderFiles returns paginated list of currently needed files in
// progress, queued, and to be queued on next puller iteration, as well as the
// total number of files currently needed.
func (m *Model) RemoteNeedFolderFiles(device protocol.DeviceID, folder string, page, perpage int) ([]db.FileInfoTruncated, error) {
func (m *model) RemoteNeedFolderFiles(device protocol.DeviceID, folder string, page, perpage int) ([]db.FileInfoTruncated, error) {
m.fmut.RLock()
m.pmut.RLock()
if err := m.checkDeviceFolderConnectedLocked(device, folder); err != nil {
@ -891,17 +941,17 @@ func (m *Model) RemoteNeedFolderFiles(device protocol.DeviceID, folder string, p
// Index is called when a new device is connected and we receive their full index.
// Implements the protocol.Model interface.
func (m *Model) Index(deviceID protocol.DeviceID, folder string, fs []protocol.FileInfo) {
func (m *model) Index(deviceID protocol.DeviceID, folder string, fs []protocol.FileInfo) {
m.handleIndex(deviceID, folder, fs, false)
}
// IndexUpdate is called for incremental updates to connected devices' indexes.
// Implements the protocol.Model interface.
func (m *Model) IndexUpdate(deviceID protocol.DeviceID, folder string, fs []protocol.FileInfo) {
func (m *model) IndexUpdate(deviceID protocol.DeviceID, folder string, fs []protocol.FileInfo) {
m.handleIndex(deviceID, folder, fs, true)
}
func (m *Model) handleIndex(deviceID protocol.DeviceID, folder string, fs []protocol.FileInfo, update bool) {
func (m *model) handleIndex(deviceID protocol.DeviceID, folder string, fs []protocol.FileInfo, update bool) {
op := "Index"
if update {
op += " update"
@ -956,7 +1006,7 @@ func (m *Model) handleIndex(deviceID protocol.DeviceID, folder string, fs []prot
})
}
func (m *Model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterConfig) {
func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterConfig) {
// Check the peer device's announced folders against our own. Emits events
// for folders that we don't expect (unknown or not shared).
// Also, collect a list of folders we do share, and if he's interested in
@ -1136,7 +1186,7 @@ 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) {
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.
@ -1192,7 +1242,7 @@ func (m *Model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm
}
// 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, cm protocol.ClusterConfig, foldersDevices folderDeviceSet) bool {
changed := false
devicesNotIntroduced := make(map[protocol.DeviceID]struct{})
@ -1249,7 +1299,7 @@ func (m *Model) handleDeintroductions(introducerCfg config.DeviceConfiguration,
// handleAutoAccepts handles adding and sharing folders for devices that have
// AutoAcceptFolders set to true.
func (m *Model) handleAutoAccepts(deviceCfg config.DeviceConfiguration, folder protocol.Folder) bool {
func (m *model) handleAutoAccepts(deviceCfg config.DeviceConfiguration, folder protocol.Folder) bool {
if cfg, ok := m.cfg.Folder(folder.ID); !ok {
defaultPath := m.cfg.Options().DefaultFolderPath
defaultPathFs := fs.NewFilesystem(fs.FilesystemTypeBasic, defaultPath)
@ -1295,7 +1345,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) {
addresses := []string{"dynamic"}
for _, addr := range device.Addresses {
if addr != "dynamic" {
@ -1324,7 +1374,7 @@ func (m *Model) introduceDevice(device protocol.Device, introducerCfg config.Dev
}
// Closed is called when a connection has been closed
func (m *Model) Closed(conn protocol.Connection, err error) {
func (m *model) Closed(conn protocol.Connection, err error) {
device := conn.ID()
m.pmut.Lock()
@ -1350,14 +1400,14 @@ func (m *Model) Closed(conn protocol.Connection, err error) {
}
// close will close the underlying connection for a given device
func (m *Model) close(device protocol.DeviceID, err error) {
func (m *model) close(device protocol.DeviceID, err error) {
m.pmut.Lock()
m.closeLocked(device, err)
m.pmut.Unlock()
}
// closeLocked will close the underlying connection for a given device
func (m *Model) closeLocked(device protocol.DeviceID, err error) {
func (m *model) closeLocked(device protocol.DeviceID, err error) {
conn, ok := m.conn[device]
if !ok {
// There is no connection to close
@ -1398,7 +1448,7 @@ func (r *requestResponse) Wait() {
// Request returns the specified data segment by reading it from local disk.
// Implements the protocol.Model interface.
func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (out protocol.RequestResponse, err error) {
func (m *model) Request(deviceID protocol.DeviceID, folder, name string, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (out protocol.RequestResponse, err error) {
if size < 0 || offset < 0 {
return nil, protocol.ErrInvalid
}
@ -1519,7 +1569,7 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, size in
return res, nil
}
func (m *Model) recheckFile(deviceID protocol.DeviceID, folderFs fs.Filesystem, folder, name string, blockIndex int, hash []byte) {
func (m *model) recheckFile(deviceID protocol.DeviceID, folderFs fs.Filesystem, folder, name string, blockIndex int, hash []byte) {
cf, ok := m.CurrentFolderFile(folder, name)
if !ok {
l.Debugf("%v recheckFile: %s: %q / %q: no current file", m, deviceID, folder, name)
@ -1560,7 +1610,7 @@ func (m *Model) recheckFile(deviceID protocol.DeviceID, folderFs fs.Filesystem,
}
}
func (m *Model) CurrentFolderFile(folder string, file string) (protocol.FileInfo, bool) {
func (m *model) CurrentFolderFile(folder string, file string) (protocol.FileInfo, bool) {
m.fmut.RLock()
fs, ok := m.folderFiles[folder]
m.fmut.RUnlock()
@ -1570,7 +1620,7 @@ func (m *Model) CurrentFolderFile(folder string, file string) (protocol.FileInfo
return fs.Get(protocol.LocalDeviceID, file)
}
func (m *Model) CurrentGlobalFile(folder string, file string) (protocol.FileInfo, bool) {
func (m *model) CurrentGlobalFile(folder string, file string) (protocol.FileInfo, bool) {
m.fmut.RLock()
fs, ok := m.folderFiles[folder]
m.fmut.RUnlock()
@ -1581,7 +1631,7 @@ func (m *Model) CurrentGlobalFile(folder string, file string) (protocol.FileInfo
}
type cFiler struct {
m *Model
m Model
r string
}
@ -1591,7 +1641,7 @@ func (cf cFiler) CurrentFile(file string) (protocol.FileInfo, bool) {
}
// Connection returns the current connection for device, and a boolean whether a connection was found.
func (m *Model) Connection(deviceID protocol.DeviceID) (connections.Connection, bool) {
func (m *model) Connection(deviceID protocol.DeviceID) (connections.Connection, bool) {
m.pmut.RLock()
cn, ok := m.conn[deviceID]
m.pmut.RUnlock()
@ -1601,7 +1651,7 @@ func (m *Model) Connection(deviceID protocol.DeviceID) (connections.Connection,
return cn, ok
}
func (m *Model) GetIgnores(folder string) ([]string, []string, error) {
func (m *model) GetIgnores(folder string) ([]string, []string, error) {
m.fmut.RLock()
defer m.fmut.RUnlock()
@ -1630,7 +1680,7 @@ func (m *Model) GetIgnores(folder string) ([]string, []string, error) {
return ignores.Lines(), ignores.Patterns(), nil
}
func (m *Model) SetIgnores(folder string, content []string) error {
func (m *model) SetIgnores(folder string, content []string) error {
cfg, ok := m.cfg.Folders()[folder]
if !ok {
return fmt.Errorf("folder %s does not exist", cfg.Description())
@ -1664,7 +1714,7 @@ func (m *Model) SetIgnores(folder string, content []string) error {
// OnHello is called when an device connects to us.
// This allows us to extract some information from the Hello message
// and add it to a list of known devices ahead of any checks.
func (m *Model) OnHello(remoteID protocol.DeviceID, addr net.Addr, hello protocol.HelloResult) error {
func (m *model) OnHello(remoteID protocol.DeviceID, addr net.Addr, hello protocol.HelloResult) error {
if m.cfg.IgnoredDevice(remoteID) {
return errDeviceIgnored
}
@ -1694,7 +1744,7 @@ func (m *Model) OnHello(remoteID protocol.DeviceID, addr net.Addr, hello protoco
}
// GetHello is called when we are about to connect to some remote device.
func (m *Model) GetHello(id protocol.DeviceID) protocol.HelloIntf {
func (m *model) GetHello(id protocol.DeviceID) protocol.HelloIntf {
name := ""
if _, ok := m.cfg.Device(id); ok {
name = m.cfg.MyName()
@ -1709,7 +1759,7 @@ func (m *Model) GetHello(id protocol.DeviceID) protocol.HelloIntf {
// AddConnection adds a new peer connection to the model. An initial index will
// be sent to the connected peer, thereafter index updates whenever the local
// folder changes.
func (m *Model) AddConnection(conn connections.Connection, hello protocol.HelloResult) {
func (m *model) AddConnection(conn connections.Connection, hello protocol.HelloResult) {
deviceID := conn.ID()
device, ok := m.cfg.Device(deviceID)
if !ok {
@ -1778,7 +1828,7 @@ func (m *Model) AddConnection(conn connections.Connection, hello protocol.HelloR
m.deviceWasSeen(deviceID)
}
func (m *Model) DownloadProgress(device protocol.DeviceID, folder string, updates []protocol.FileDownloadProgressUpdate) {
func (m *model) DownloadProgress(device protocol.DeviceID, folder string, updates []protocol.FileDownloadProgressUpdate) {
m.fmut.RLock()
cfg, ok := m.folderCfgs[folder]
m.fmut.RUnlock()
@ -1799,7 +1849,7 @@ func (m *Model) DownloadProgress(device protocol.DeviceID, folder string, update
})
}
func (m *Model) deviceStatRef(deviceID protocol.DeviceID) *stats.DeviceStatisticsReference {
func (m *model) deviceStatRef(deviceID protocol.DeviceID) *stats.DeviceStatisticsReference {
m.fmut.Lock()
defer m.fmut.Unlock()
@ -1812,11 +1862,11 @@ func (m *Model) deviceStatRef(deviceID protocol.DeviceID) *stats.DeviceStatistic
return sr
}
func (m *Model) deviceWasSeen(deviceID protocol.DeviceID) {
func (m *model) deviceWasSeen(deviceID protocol.DeviceID) {
m.deviceStatRef(deviceID).WasSeen()
}
func (m *Model) folderStatRef(folder string) *stats.FolderStatisticsReference {
func (m *model) folderStatRef(folder string) *stats.FolderStatisticsReference {
m.fmut.Lock()
defer m.fmut.Unlock()
@ -1828,7 +1878,7 @@ func (m *Model) folderStatRef(folder string) *stats.FolderStatisticsReference {
return sr
}
func (m *Model) receivedFile(folder string, file protocol.FileInfo) {
func (m *model) receivedFile(folder string, file protocol.FileInfo) {
m.folderStatRef(folder).ReceivedFile(file.Name, file.IsDeleted())
}
@ -1949,7 +1999,7 @@ func sendIndexTo(prevSequence int64, conn protocol.Connection, folder string, fs
return f.Sequence, err
}
func (m *Model) updateLocalsFromScanning(folder string, fs []protocol.FileInfo) {
func (m *model) updateLocalsFromScanning(folder string, fs []protocol.FileInfo) {
m.updateLocals(folder, fs)
m.fmut.RLock()
@ -1959,7 +2009,7 @@ func (m *Model) updateLocalsFromScanning(folder string, fs []protocol.FileInfo)
m.diskChangeDetected(folderCfg, fs, events.LocalChangeDetected)
}
func (m *Model) updateLocalsFromPulling(folder string, fs []protocol.FileInfo) {
func (m *model) updateLocalsFromPulling(folder string, fs []protocol.FileInfo) {
m.updateLocals(folder, fs)
m.fmut.RLock()
@ -1969,7 +2019,7 @@ func (m *Model) updateLocalsFromPulling(folder string, fs []protocol.FileInfo) {
m.diskChangeDetected(folderCfg, fs, events.RemoteChangeDetected)
}
func (m *Model) updateLocals(folder string, fs []protocol.FileInfo) {
func (m *model) updateLocals(folder string, fs []protocol.FileInfo) {
m.fmut.RLock()
files := m.folderFiles[folder]
m.fmut.RUnlock()
@ -1992,7 +2042,7 @@ func (m *Model) updateLocals(folder string, fs []protocol.FileInfo) {
})
}
func (m *Model) diskChangeDetected(folderCfg config.FolderConfiguration, files []protocol.FileInfo, typeOfEvent events.EventType) {
func (m *model) diskChangeDetected(folderCfg config.FolderConfiguration, files []protocol.FileInfo, typeOfEvent events.EventType) {
for _, file := range files {
if file.IsInvalid() {
continue
@ -2035,7 +2085,7 @@ func (m *Model) diskChangeDetected(folderCfg config.FolderConfiguration, files [
}
}
func (m *Model) requestGlobal(deviceID protocol.DeviceID, folder, name string, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
func (m *model) requestGlobal(deviceID protocol.DeviceID, folder, name string, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
m.pmut.RLock()
nc, ok := m.conn[deviceID]
m.pmut.RUnlock()
@ -2049,7 +2099,7 @@ func (m *Model) requestGlobal(deviceID protocol.DeviceID, folder, name string, o
return nc.Request(folder, name, offset, size, hash, weakHash, fromTemporary)
}
func (m *Model) ScanFolders() map[string]error {
func (m *model) ScanFolders() map[string]error {
m.fmut.RLock()
folders := make([]string, 0, len(m.folderCfgs))
for folder := range m.folderCfgs {
@ -2087,11 +2137,11 @@ func (m *Model) ScanFolders() map[string]error {
return errors
}
func (m *Model) ScanFolder(folder string) error {
func (m *model) ScanFolder(folder string) error {
return m.ScanFolderSubdirs(folder, nil)
}
func (m *Model) ScanFolderSubdirs(folder string, subs []string) error {
func (m *model) ScanFolderSubdirs(folder string, subs []string) error {
m.fmut.RLock()
if err := m.checkFolderRunningLocked(folder); err != nil {
m.fmut.RUnlock()
@ -2103,7 +2153,7 @@ func (m *Model) ScanFolderSubdirs(folder string, subs []string) error {
return runner.Scan(subs)
}
func (m *Model) DelayScan(folder string, next time.Duration) {
func (m *model) DelayScan(folder string, next time.Duration) {
m.fmut.Lock()
runner, ok := m.folderRunners[folder]
m.fmut.Unlock()
@ -2115,7 +2165,7 @@ func (m *Model) DelayScan(folder string, next time.Duration) {
// numHashers returns the number of hasher routines to use for a given folder,
// taking into account configuration and available CPU cores.
func (m *Model) numHashers(folder string) int {
func (m *model) numHashers(folder string) int {
m.fmut.Lock()
folderCfg := m.folderCfgs[folder]
numFolders := len(m.folderCfgs)
@ -2144,7 +2194,7 @@ func (m *Model) numHashers(folder string) int {
// generateClusterConfig returns a ClusterConfigMessage that is correct for
// the given peer device
func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.ClusterConfig {
func (m *model) generateClusterConfig(device protocol.DeviceID) protocol.ClusterConfig {
var message protocol.ClusterConfig
m.fmut.RLock()
@ -2201,7 +2251,7 @@ func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster
return message
}
func (m *Model) State(folder string) (string, time.Time, error) {
func (m *model) State(folder string) (string, time.Time, error) {
m.fmut.RLock()
runner, ok := m.folderRunners[folder]
m.fmut.RUnlock()
@ -2215,7 +2265,7 @@ func (m *Model) State(folder string) (string, time.Time, error) {
return state.String(), changed, err
}
func (m *Model) FolderErrors(folder string) ([]FileError, error) {
func (m *model) FolderErrors(folder string) ([]FileError, error) {
m.fmut.RLock()
defer m.fmut.RUnlock()
if err := m.checkFolderRunningLocked(folder); err != nil {
@ -2224,7 +2274,7 @@ func (m *Model) FolderErrors(folder string) ([]FileError, error) {
return m.folderRunners[folder].Errors(), nil
}
func (m *Model) WatchError(folder string) error {
func (m *model) WatchError(folder string) error {
m.fmut.RLock()
defer m.fmut.RUnlock()
if err := m.checkFolderRunningLocked(folder); err != nil {
@ -2233,7 +2283,7 @@ func (m *Model) WatchError(folder string) error {
return m.folderRunners[folder].WatchError()
}
func (m *Model) Override(folder string) {
func (m *model) Override(folder string) {
// Grab the runner and the file set.
m.fmut.RLock()
@ -2251,7 +2301,7 @@ func (m *Model) Override(folder string) {
})
}
func (m *Model) Revert(folder string) {
func (m *model) Revert(folder string) {
// Grab the runner and the file set.
m.fmut.RLock()
@ -2272,7 +2322,7 @@ func (m *Model) Revert(folder string) {
// CurrentSequence returns the change version for the given folder.
// This is guaranteed to increment if the contents of the local folder has
// changed.
func (m *Model) CurrentSequence(folder string) (int64, bool) {
func (m *model) CurrentSequence(folder string) (int64, bool) {
m.fmut.RLock()
fs, ok := m.folderFiles[folder]
m.fmut.RUnlock()
@ -2288,7 +2338,7 @@ func (m *Model) CurrentSequence(folder string) (int64, bool) {
// RemoteSequence returns the change version for the given folder, as
// sent by remote peers. This is guaranteed to increment if the contents of
// the remote or global folder has changed.
func (m *Model) RemoteSequence(folder string) (int64, bool) {
func (m *model) RemoteSequence(folder string) (int64, bool) {
m.fmut.RLock()
defer m.fmut.RUnlock()
@ -2308,7 +2358,7 @@ func (m *Model) RemoteSequence(folder string) (int64, bool) {
return ver, true
}
func (m *Model) GlobalDirectoryTree(folder, prefix string, levels int, dirsonly bool) map[string]interface{} {
func (m *model) GlobalDirectoryTree(folder, prefix string, levels int, dirsonly bool) map[string]interface{} {
m.fmut.RLock()
files, ok := m.folderFiles[folder]
m.fmut.RUnlock()
@ -2372,7 +2422,7 @@ func (m *Model) GlobalDirectoryTree(folder, prefix string, levels int, dirsonly
return output
}
func (m *Model) GetFolderVersions(folder string) (map[string][]versioner.FileVersion, error) {
func (m *model) GetFolderVersions(folder string) (map[string][]versioner.FileVersion, error) {
fcfg, ok := m.cfg.Folder(folder)
if !ok {
return nil, errFolderMissing
@ -2432,7 +2482,7 @@ func (m *Model) GetFolderVersions(folder string) (map[string][]versioner.FileVer
return files, nil
}
func (m *Model) RestoreFolderVersions(folder string, versions map[string]time.Time) (map[string]string, error) {
func (m *model) RestoreFolderVersions(folder string, versions map[string]time.Time) (map[string]string, error) {
fcfg, ok := m.cfg.Folder(folder)
if !ok {
return nil, errFolderMissing
@ -2503,7 +2553,7 @@ func (m *Model) RestoreFolderVersions(folder string, versions map[string]time.Ti
return errors, nil
}
func (m *Model) Availability(folder string, file protocol.FileInfo, block protocol.BlockInfo) []Availability {
func (m *model) Availability(folder string, file protocol.FileInfo, block protocol.BlockInfo) []Availability {
// The slightly unusual locking sequence here is because we need to hold
// pmut for the duration (as the value returned from foldersFiles can
// get heavily modified on Close()), but also must acquire fmut before
@ -2544,7 +2594,7 @@ next:
}
// BringToFront bumps the given files priority in the job queue.
func (m *Model) BringToFront(folder, file string) {
func (m *model) BringToFront(folder, file string) {
m.pmut.RLock()
defer m.pmut.RUnlock()
@ -2554,20 +2604,20 @@ func (m *Model) BringToFront(folder, file string) {
}
}
func (m *Model) ResetFolder(folder string) {
func (m *model) ResetFolder(folder string) {
l.Infof("Cleaning data for folder %q", folder)
db.DropFolder(m.db, folder)
}
func (m *Model) String() string {
func (m *model) String() string {
return fmt.Sprintf("model@%p", m)
}
func (m *Model) VerifyConfiguration(from, to config.Configuration) error {
func (m *model) VerifyConfiguration(from, to config.Configuration) error {
return nil
}
func (m *Model) CommitConfiguration(from, to config.Configuration) bool {
func (m *model) CommitConfiguration(from, to config.Configuration) bool {
// TODO: This should not use reflect, and should take more care to try to handle stuff without restart.
// Go through the folder configs and figure out if we need to restart or not.
@ -2661,7 +2711,7 @@ func (m *Model) CommitConfiguration(from, to config.Configuration) bool {
// checkFolderRunningLocked returns nil if the folder is up and running and a
// descriptive error if not.
// Need to hold (read) lock on m.fmut when calling this.
func (m *Model) checkFolderRunningLocked(folder string) error {
func (m *model) checkFolderRunningLocked(folder string) error {
_, ok := m.folderRunners[folder]
if ok {
return nil
@ -2679,7 +2729,7 @@ func (m *Model) checkFolderRunningLocked(folder string) error {
// checkFolderDeviceStatusLocked first checks the folder and then whether the
// given device is connected and shares this folder.
// Need to hold (read) lock on both m.fmut and m.pmut when calling this.
func (m *Model) checkDeviceFolderConnectedLocked(device protocol.DeviceID, folder string) error {
func (m *model) checkDeviceFolderConnectedLocked(device protocol.DeviceID, folder string) error {
if err := m.checkFolderRunningLocked(folder); err != nil {
return err
}

View File

@ -38,7 +38,7 @@ import (
)
var myID, device1, device2 protocol.DeviceID
var defaultCfgWrapper *config.Wrapper
var defaultCfgWrapper config.Wrapper
var defaultFolderConfig config.FolderConfiguration
var defaultFs fs.Filesystem
var defaultCfg config.Configuration
@ -161,7 +161,7 @@ func prepareTmpFile(to fs.Filesystem) (string, error) {
return tmpName, nil
}
func createTmpWrapper(cfg config.Configuration) *config.Wrapper {
func createTmpWrapper(cfg config.Configuration) config.Wrapper {
tmpFile, err := ioutil.TempFile(tmpLocation, "syncthing-testConfig-")
if err != nil {
panic(err)
@ -171,7 +171,11 @@ func createTmpWrapper(cfg config.Configuration) *config.Wrapper {
return wrapper
}
func newState(cfg config.Configuration) (*config.Wrapper, *Model) {
func newModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersion string, ldb *db.Lowlevel, protectedFiles []string) *model {
return NewModel(cfg, id, clientName, clientVersion, ldb, protectedFiles).(*model)
}
func newState(cfg config.Configuration) (config.Wrapper, *model) {
wcfg := createTmpWrapper(cfg)
m := setupModel(wcfg)
@ -183,9 +187,9 @@ func newState(cfg config.Configuration) (*config.Wrapper, *Model) {
return wcfg, m
}
func setupModel(w *config.Wrapper) *Model {
func setupModel(w config.Wrapper) *model {
db := db.OpenMemory()
m := NewModel(w, myID, "syncthing", "dev", db, nil)
m := newModel(w, myID, "syncthing", "dev", db, nil)
m.ServeBackground()
for id, cfg := range w.Folders() {
if !cfg.Paused {
@ -322,7 +326,7 @@ type fakeConnection struct {
files []protocol.FileInfo
fileData map[string][]byte
folder string
model *Model
model *model
indexFn func(string, []protocol.FileInfo)
requestFn func(folder, name string, offset int64, size int, hash []byte, fromTemporary bool) ([]byte, error)
mut sync.Mutex
@ -563,7 +567,7 @@ func TestDeviceRename(t *testing.T) {
cfg := config.Wrap("testdata/tmpconfig.xml", rawCfg)
db := db.OpenMemory()
m := NewModel(cfg, myID, "syncthing", "dev", db, nil)
m := newModel(cfg, myID, "syncthing", "dev", db, nil)
if cfg.Devices()[device1].Name != "" {
t.Errorf("Device already has a name")
@ -662,7 +666,7 @@ func TestClusterConfig(t *testing.T) {
wrapper := createTmpWrapper(cfg)
defer os.Remove(wrapper.ConfigPath())
m := NewModel(wrapper, myID, "syncthing", "dev", db, nil)
m := newModel(wrapper, myID, "syncthing", "dev", db, nil)
m.AddFolder(cfg.Folders[0])
m.AddFolder(cfg.Folders[1])
m.ServeBackground()
@ -1644,7 +1648,7 @@ func TestAutoAcceptPausedWhenFolderConfigNotChanged(t *testing.T) {
}
}
func changeIgnores(t *testing.T, m *Model, expected []string) {
func changeIgnores(t *testing.T, m *model, expected []string) {
arrEqual := func(a, b []string) bool {
if len(a) != len(b) {
return false
@ -1796,7 +1800,7 @@ func TestROScanRecovery(t *testing.T) {
testOs.RemoveAll(fcfg.Path)
m := NewModel(cfg, myID, "syncthing", "dev", ldb, nil)
m := newModel(cfg, myID, "syncthing", "dev", ldb, nil)
m.AddFolder(fcfg)
m.StartFolder("default")
m.ServeBackground()
@ -1883,7 +1887,7 @@ func TestRWScanRecovery(t *testing.T) {
testOs.RemoveAll(fcfg.Path)
m := NewModel(cfg, myID, "syncthing", "dev", ldb, nil)
m := newModel(cfg, myID, "syncthing", "dev", ldb, nil)
m.AddFolder(fcfg)
m.StartFolder("default")
m.ServeBackground()
@ -1941,7 +1945,7 @@ func TestRWScanRecovery(t *testing.T) {
func TestGlobalDirectoryTree(t *testing.T) {
db := db.OpenMemory()
m := NewModel(defaultCfgWrapper, myID, "syncthing", "dev", db, nil)
m := newModel(defaultCfgWrapper, myID, "syncthing", "dev", db, nil)
m.AddFolder(defaultFolderConfig)
m.ServeBackground()
defer m.Stop()
@ -2193,7 +2197,7 @@ func TestGlobalDirectoryTree(t *testing.T) {
func TestGlobalDirectorySelfFixing(t *testing.T) {
db := db.OpenMemory()
m := NewModel(defaultCfgWrapper, myID, "syncthing", "dev", db, nil)
m := newModel(defaultCfgWrapper, myID, "syncthing", "dev", db, nil)
m.AddFolder(defaultFolderConfig)
m.ServeBackground()
@ -2368,7 +2372,7 @@ func BenchmarkTree_100_10(b *testing.B) {
func benchmarkTree(b *testing.B, n1, n2 int) {
db := db.OpenMemory()
m := NewModel(defaultCfgWrapper, myID, "syncthing", "dev", db, nil)
m := newModel(defaultCfgWrapper, myID, "syncthing", "dev", db, nil)
m.AddFolder(defaultFolderConfig)
m.ServeBackground()
@ -2438,7 +2442,7 @@ func TestIssue4357(t *testing.T) {
// Create a separate wrapper not to pollute other tests.
wrapper := createTmpWrapper(config.Configuration{})
defer os.Remove(wrapper.ConfigPath())
m := NewModel(wrapper, myID, "syncthing", "dev", db, nil)
m := newModel(wrapper, myID, "syncthing", "dev", db, nil)
m.ServeBackground()
defer m.Stop()
@ -2568,7 +2572,7 @@ func TestIndexesForUnknownDevicesDropped(t *testing.T) {
t.Error("expected two devices")
}
m := NewModel(defaultCfgWrapper, myID, "syncthing", "dev", dbi, nil)
m := newModel(defaultCfgWrapper, myID, "syncthing", "dev", dbi, nil)
m.AddFolder(defaultFolderConfig)
m.StartFolder("default")
@ -3055,7 +3059,7 @@ func TestCustomMarkerName(t *testing.T) {
testOs.RemoveAll(fcfg.Path)
defer testOs.RemoveAll(fcfg.Path)
m := NewModel(cfg, myID, "syncthing", "dev", ldb, nil)
m := newModel(cfg, myID, "syncthing", "dev", ldb, nil)
m.AddFolder(fcfg)
m.StartFolder("default")
m.ServeBackground()
@ -3466,7 +3470,7 @@ func TestIssue4094(t *testing.T) {
// Create a separate wrapper not to pollute other tests.
wrapper := createTmpWrapper(config.Configuration{})
defer os.Remove(wrapper.ConfigPath())
m := NewModel(wrapper, myID, "syncthing", "dev", db, nil)
m := newModel(wrapper, myID, "syncthing", "dev", db, nil)
m.ServeBackground()
defer m.Stop()
@ -3505,7 +3509,7 @@ func TestIssue4903(t *testing.T) {
// Create a separate wrapper not to pollute other tests.
wrapper := createTmpWrapper(config.Configuration{})
defer os.Remove(wrapper.ConfigPath())
m := NewModel(wrapper, myID, "syncthing", "dev", db, nil)
m := newModel(wrapper, myID, "syncthing", "dev", db, nil)
m.ServeBackground()
defer m.Stop()
@ -3575,7 +3579,7 @@ func TestParentOfUnignored(t *testing.T) {
}
}
func addFakeConn(m *Model, dev protocol.DeviceID) *fakeConnection {
func addFakeConn(m *model, dev protocol.DeviceID) *fakeConnection {
fc := &fakeConnection{id: dev, model: m}
m.AddConnection(fc, protocol.HelloResult{})

View File

@ -31,7 +31,7 @@ type ProgressEmitter struct {
// NewProgressEmitter creates a new progress emitter which emits
// DownloadProgress events every interval.
func NewProgressEmitter(cfg *config.Wrapper) *ProgressEmitter {
func NewProgressEmitter(cfg config.Wrapper) *ProgressEmitter {
t := &ProgressEmitter{
stop: make(chan struct{}),
registry: make(map[string]*sharedPullerState),

View File

@ -684,7 +684,7 @@ func TestRequestSymlinkWindows(t *testing.T) {
}
}
func tmpDefaultWrapper() (*config.Wrapper, string) {
func tmpDefaultWrapper() (config.Wrapper, string) {
w := createTmpWrapper(defaultCfgWrapper.RawCopy())
fcfg, tmpDir := testFolderConfigTmp()
w.SetFolder(fcfg)
@ -703,13 +703,13 @@ func testFolderConfig(path string) config.FolderConfiguration {
return cfg
}
func setupModelWithConnection() (*Model, *fakeConnection, string, *config.Wrapper) {
func setupModelWithConnection() (*model, *fakeConnection, string, config.Wrapper) {
w, tmpDir := tmpDefaultWrapper()
m, fc := setupModelWithConnectionFromWrapper(w)
return m, fc, tmpDir, w
}
func setupModelWithConnectionFromWrapper(w *config.Wrapper) (*Model, *fakeConnection) {
func setupModelWithConnectionFromWrapper(w config.Wrapper) (*model, *fakeConnection) {
m := setupModel(w)
fc := addFakeConn(m, device1)

View File

@ -23,7 +23,7 @@ import (
// setup/renewal of a port mapping.
type Service struct {
id protocol.DeviceID
cfg *config.Wrapper
cfg config.Wrapper
stop chan struct{}
mappings []*Mapping
@ -31,7 +31,7 @@ type Service struct {
mut sync.RWMutex
}
func NewService(id protocol.DeviceID, cfg *config.Wrapper) *Service {
func NewService(id protocol.DeviceID, cfg config.Wrapper) *Service {
return &Service{
id: id,
cfg: cfg,

View File

@ -125,14 +125,14 @@ func newAggregator(folderCfg config.FolderConfiguration, ctx context.Context) *a
return a
}
func Aggregate(in <-chan fs.Event, out chan<- []string, folderCfg config.FolderConfiguration, cfg *config.Wrapper, ctx context.Context) {
func Aggregate(in <-chan fs.Event, out chan<- []string, folderCfg config.FolderConfiguration, cfg config.Wrapper, ctx context.Context) {
a := newAggregator(folderCfg, ctx)
// Necessary for unit tests where the backend is mocked
go a.mainLoop(in, out, cfg)
}
func (a *aggregator) mainLoop(in <-chan fs.Event, out chan<- []string, cfg *config.Wrapper) {
func (a *aggregator) mainLoop(in <-chan fs.Event, out chan<- []string, cfg config.Wrapper) {
a.notifyTimer = time.NewTimer(a.notifyDelay)
defer a.notifyTimer.Stop()