|
@@ -100,8 +100,11 @@ type Model struct {
|
|
|
pmut sync.RWMutex // protects the above
|
|
|
}
|
|
|
|
|
|
+type folderFactory func(*Model, config.FolderConfiguration, versioner.Versioner) service
|
|
|
+
|
|
|
var (
|
|
|
- symlinkWarning = stdsync.Once{}
|
|
|
+ symlinkWarning = stdsync.Once{}
|
|
|
+ folderFactories = make(map[string]folderFactory, 0)
|
|
|
)
|
|
|
|
|
|
// NewModel creates and starts a new model. The model starts in read-only mode,
|
|
@@ -158,10 +161,8 @@ func (m *Model) StartDeadlockDetector(timeout time.Duration) {
|
|
|
deadlockDetect(m.pmut, timeout)
|
|
|
}
|
|
|
|
|
|
-// StartFolderRW starts read/write processing on the current model. When in
|
|
|
-// read/write mode the model will attempt to keep in sync with the cluster by
|
|
|
-// pulling needed files from peer devices.
|
|
|
-func (m *Model) StartFolderRW(folder string) {
|
|
|
+// StartFolder constrcuts the folder service and starts it.
|
|
|
+func (m *Model) StartFolder(folder string) {
|
|
|
m.fmut.Lock()
|
|
|
cfg, ok := m.folderCfgs[folder]
|
|
|
if !ok {
|
|
@@ -172,37 +173,43 @@ func (m *Model) StartFolderRW(folder string) {
|
|
|
if ok {
|
|
|
panic("cannot start already running folder " + folder)
|
|
|
}
|
|
|
- p := newRWFolder(m, cfg)
|
|
|
- m.folderRunners[folder] = p
|
|
|
|
|
|
+ folderFactory, ok := folderFactories[cfg.Type]
|
|
|
+ if !ok {
|
|
|
+ panic("unknown folder type " + cfg.Type)
|
|
|
+ }
|
|
|
+
|
|
|
+ var ver versioner.Versioner
|
|
|
if len(cfg.Versioning.Type) > 0 {
|
|
|
- factory, ok := versioner.Factories[cfg.Versioning.Type]
|
|
|
+ versionerFactory, ok := versioner.Factories[cfg.Versioning.Type]
|
|
|
if !ok {
|
|
|
l.Fatalf("Requested versioning type %q that does not exist", cfg.Versioning.Type)
|
|
|
}
|
|
|
|
|
|
- versioner := factory(folder, cfg.Path(), cfg.Versioning.Params)
|
|
|
- if service, ok := versioner.(suture.Service); ok {
|
|
|
+ ver = versionerFactory(folder, cfg.Path(), cfg.Versioning.Params)
|
|
|
+ if service, ok := ver.(suture.Service); ok {
|
|
|
// The versioner implements the suture.Service interface, so
|
|
|
// expects to be run in the background in addition to being called
|
|
|
// when files are going to be archived.
|
|
|
token := m.Add(service)
|
|
|
m.folderRunnerTokens[folder] = append(m.folderRunnerTokens[folder], token)
|
|
|
}
|
|
|
- p.versioner = versioner
|
|
|
}
|
|
|
|
|
|
+ p := folderFactory(m, cfg, ver)
|
|
|
+ m.folderRunners[folder] = p
|
|
|
+
|
|
|
m.warnAboutOverwritingProtectedFiles(folder)
|
|
|
|
|
|
token := m.Add(p)
|
|
|
m.folderRunnerTokens[folder] = append(m.folderRunnerTokens[folder], token)
|
|
|
m.fmut.Unlock()
|
|
|
|
|
|
- l.Infoln("Ready to synchronize", folder, "(read-write)")
|
|
|
+ l.Infoln("Ready to synchronize", folder, fmt.Sprintf("(%s)", cfg.Type))
|
|
|
}
|
|
|
|
|
|
func (m *Model) warnAboutOverwritingProtectedFiles(folder string) {
|
|
|
- if m.folderCfgs[folder].ReadOnly {
|
|
|
+ if m.folderCfgs[folder].Type == config.FolderTypeReadOnly {
|
|
|
return
|
|
|
}
|
|
|
|
|
@@ -229,30 +236,6 @@ func (m *Model) warnAboutOverwritingProtectedFiles(folder string) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// StartFolderRO starts read only processing on the current model. When in
|
|
|
-// read only mode the model will announce files to the cluster but not pull in
|
|
|
-// any external changes.
|
|
|
-func (m *Model) StartFolderRO(folder string) {
|
|
|
- m.fmut.Lock()
|
|
|
- cfg, ok := m.folderCfgs[folder]
|
|
|
- if !ok {
|
|
|
- panic("cannot start nonexistent folder " + folder)
|
|
|
- }
|
|
|
-
|
|
|
- _, ok = m.folderRunners[folder]
|
|
|
- if ok {
|
|
|
- panic("cannot start already running folder " + folder)
|
|
|
- }
|
|
|
- s := newROFolder(m, cfg)
|
|
|
- m.folderRunners[folder] = s
|
|
|
-
|
|
|
- token := m.Add(s)
|
|
|
- m.folderRunnerTokens[folder] = append(m.folderRunnerTokens[folder], token)
|
|
|
- m.fmut.Unlock()
|
|
|
-
|
|
|
- l.Infoln("Ready to synchronize", folder, "(read only; no external updates accepted)")
|
|
|
-}
|
|
|
-
|
|
|
func (m *Model) RemoveFolder(folder string) {
|
|
|
m.fmut.Lock()
|
|
|
m.pmut.Lock()
|
|
@@ -1093,7 +1076,7 @@ func (m *Model) DownloadProgress(device protocol.DeviceID, folder string, update
|
|
|
cfg, ok := m.folderCfgs[folder]
|
|
|
m.fmut.RUnlock()
|
|
|
|
|
|
- if !ok || cfg.ReadOnly || cfg.DisableTempIndexes {
|
|
|
+ if !ok || cfg.Type == config.FolderTypeReadOnly || cfg.DisableTempIndexes {
|
|
|
return
|
|
|
}
|
|
|
|
|
@@ -1606,7 +1589,7 @@ func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster
|
|
|
Label: folderCfg.Label,
|
|
|
}
|
|
|
var flags uint32
|
|
|
- if folderCfg.ReadOnly {
|
|
|
+ if folderCfg.Type == config.FolderTypeReadOnly {
|
|
|
flags |= protocol.FlagFolderReadOnly
|
|
|
}
|
|
|
if folderCfg.IgnorePerms {
|
|
@@ -1874,7 +1857,7 @@ func (m *Model) CheckFolderHealth(id string) error {
|
|
|
case !folder.HasMarker():
|
|
|
err = errors.New("folder marker missing")
|
|
|
|
|
|
- case !folder.ReadOnly:
|
|
|
+ case folder.Type != config.FolderTypeReadOnly:
|
|
|
// Check for free space, if it isn't a master folder. We aren't
|
|
|
// going to change the contents of master folders, so we don't
|
|
|
// care about the amount of free space there.
|
|
@@ -1951,11 +1934,7 @@ func (m *Model) CommitConfiguration(from, to config.Configuration) bool {
|
|
|
// A folder was added.
|
|
|
l.Debugln(m, "adding folder", folderID)
|
|
|
m.AddFolder(cfg)
|
|
|
- if cfg.ReadOnly {
|
|
|
- m.StartFolderRO(folderID)
|
|
|
- } else {
|
|
|
- m.StartFolderRW(folderID)
|
|
|
- }
|
|
|
+ m.StartFolder(folderID)
|
|
|
|
|
|
// Drop connections to all devices that can now share the new
|
|
|
// folder.
|