mirror of
https://github.com/octoleo/syncthing.git
synced 2025-01-22 22:58:25 +00:00
lib/model: Use factories for creating folders
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3029
This commit is contained in:
parent
6720906ee5
commit
eabd2fc936
@ -691,13 +691,7 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
|
|||||||
}
|
}
|
||||||
m.Index(device, folderCfg.ID, nil, 0, nil)
|
m.Index(device, folderCfg.ID, nil, 0, nil)
|
||||||
}
|
}
|
||||||
// Routine to pull blocks from other devices to synchronize the local
|
m.StartFolder(folderCfg.ID)
|
||||||
// folder. Does not run when we are in read only (publish only) mode.
|
|
||||||
if folderCfg.ReadOnly {
|
|
||||||
m.StartFolderRO(folderCfg.ID)
|
|
||||||
} else {
|
|
||||||
m.StartFolderRW(folderCfg.ID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mainService.Add(m)
|
mainService.Add(m)
|
||||||
@ -994,7 +988,7 @@ func defaultConfig(myName string) config.Configuration {
|
|||||||
if !noDefaultFolder {
|
if !noDefaultFolder {
|
||||||
l.Infoln("Default folder created and/or linked to new config")
|
l.Infoln("Default folder created and/or linked to new config")
|
||||||
|
|
||||||
defaultFolder = config.NewFolderConfiguration("default", locations[locDefFolder])
|
defaultFolder = config.NewFolderConfiguration("default", locations[locDefFolder], config.FolderTypeReadWrite)
|
||||||
defaultFolder.RescanIntervalS = 60
|
defaultFolder.RescanIntervalS = 60
|
||||||
defaultFolder.MinDiskFreePct = 1
|
defaultFolder.MinDiskFreePct = 1
|
||||||
defaultFolder.Devices = []config.FolderDeviceConfiguration{{DeviceID: myID}}
|
defaultFolder.Devices = []config.FolderDeviceConfiguration{{DeviceID: myID}}
|
||||||
|
@ -133,7 +133,7 @@ func reportData(cfg configIntf, m modelIntf) map[string]interface{} {
|
|||||||
for _, cfg := range cfg.Folders() {
|
for _, cfg := range cfg.Folders() {
|
||||||
rescanIntvs = append(rescanIntvs, cfg.RescanIntervalS)
|
rescanIntvs = append(rescanIntvs, cfg.RescanIntervalS)
|
||||||
|
|
||||||
if cfg.ReadOnly {
|
if cfg.Type == config.FolderTypeReadOnly {
|
||||||
folderUses["readonly"]++
|
folderUses["readonly"]++
|
||||||
}
|
}
|
||||||
if cfg.IgnorePerms {
|
if cfg.IgnorePerms {
|
||||||
|
@ -231,7 +231,7 @@
|
|||||||
<div class="panel-progress" ng-show="folderStatus(folder) == 'syncing'" ng-attr-style="width: {{syncPercentage(folder.id)}}%"></div>
|
<div class="panel-progress" ng-show="folderStatus(folder) == 'syncing'" ng-attr-style="width: {{syncPercentage(folder.id)}}%"></div>
|
||||||
<div class="panel-progress" ng-show="folderStatus(folder) == 'scanning' && scanProgress[folder.id] != undefined" ng-attr-style="width: {{scanPercentage(folder.id)}}%"></div>
|
<div class="panel-progress" ng-show="folderStatus(folder) == 'scanning' && scanProgress[folder.id] != undefined" ng-attr-style="width: {{scanPercentage(folder.id)}}%"></div>
|
||||||
<h4 class="panel-title">
|
<h4 class="panel-title">
|
||||||
<span class="fa hidden-xs fa-fw" ng-class="[folder.readOnly ? 'fa-lock' : 'fa-folder']"></span>
|
<span class="fa hidden-xs fa-fw" ng-class="[folder.type == 'readonly' ? 'fa-lock' : 'fa-folder']"></span>
|
||||||
<a href="#folder-{{$index}}">
|
<a href="#folder-{{$index}}">
|
||||||
<span ng-show="folder.label.length == 0">{{folder.id}}</span>
|
<span ng-show="folder.label.length == 0">{{folder.id}}</span>
|
||||||
<span tooltip data-original-title="{{folder.id}}" ng-show="folder.label.length != 0">{{folder.label}}</span>
|
<span tooltip data-original-title="{{folder.id}}" ng-show="folder.label.length != 0">{{folder.label}}</span>
|
||||||
@ -294,7 +294,7 @@
|
|||||||
<span tooltip data-original-title="{{scanRate(folder.id) | binary}}B/s">~ {{scanRemaining(folder.id)}}</span>
|
<span tooltip data-original-title="{{scanRate(folder.id) | binary}}B/s">~ {{scanRemaining(folder.id)}}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr ng-if="!folder.readOnly && (folderStatus(folder) === 'outofsync' || hasFailedFiles(folder.id))">
|
<tr ng-if="folder.type != 'readonly' && (folderStatus(folder) === 'outofsync' || hasFailedFiles(folder.id))">
|
||||||
<th><span class="fa fa-fw fa-exclamation-circle"></span> <span translate>Failed Items</span></th>
|
<th><span class="fa fa-fw fa-exclamation-circle"></span> <span translate>Failed Items</span></th>
|
||||||
<!-- Show the number of failed items as a link to bring up the list. -->
|
<!-- Show the number of failed items as a link to bring up the list. -->
|
||||||
<td ng-if="hasFailedFiles(folder.id)" class="text-right">
|
<td ng-if="hasFailedFiles(folder.id)" class="text-right">
|
||||||
@ -305,10 +305,11 @@
|
|||||||
<span class="fa fa-spinner fa-pulse"></span>
|
<span class="fa fa-spinner fa-pulse"></span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr ng-if="folder.readOnly">
|
<tr ng-if="folder.type != 'readwrite'">
|
||||||
<th><span class="fa fa-fw fa-lock"></span> <span translate>Folder Master</span></th>
|
<th><span class="fa fa-fw fa-lock"></span> <span translate>Folder Type</span></th>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<span translate>Yes</span>
|
<span ng-if="folder.type == 'readonly'" translate>Master</span>
|
||||||
|
<span ng-if="folder.type != 'readonly'">{{ folder.type.charAt(0).toUpperCase() + folder.type.slice(1) }}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr ng-if="model[folder.id].ignorePatterns">
|
<tr ng-if="model[folder.id].ignorePatterns">
|
||||||
@ -351,7 +352,7 @@
|
|||||||
<th><span class="fa fa-fw fa-share-alt"></span> <span translate>Shared With</span></th>
|
<th><span class="fa fa-fw fa-share-alt"></span> <span translate>Shared With</span></th>
|
||||||
<td class="text-right">{{sharesFolder(folder)}}</td>
|
<td class="text-right">{{sharesFolder(folder)}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr ng-if="!folder.readOnly && folderStats[folder.id].lastFile && folderStats[folder.id].lastFile.filename">
|
<tr ng-if="folder.type != 'readonly' && folderStats[folder.id].lastFile && folderStats[folder.id].lastFile.filename">
|
||||||
<th><span class="fa fa-fw fa-exchange"></span> <span translate>Last File Received</span></th>
|
<th><span class="fa fa-fw fa-exchange"></span> <span translate>Last File Received</span></th>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<span tooltip data-original-title="{{folderStats[folder.id].lastFile.filename}} @ {{folderStats[folder.id].lastFile.at | date:'yyyy-MM-dd HH:mm:ss'}}">
|
<span tooltip data-original-title="{{folderStats[folder.id].lastFile.filename}} @ {{folderStats[folder.id].lastFile.at | date:'yyyy-MM-dd HH:mm:ss'}}">
|
||||||
@ -365,7 +366,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-footer">
|
<div class="panel-footer">
|
||||||
<button type="button" class="btn btn-sm btn-danger pull-left" ng-click="override(folder.id)" ng-if="folderStatus(folder) == 'outofsync' && folder.readOnly">
|
<button type="button" class="btn btn-sm btn-danger pull-left" ng-click="override(folder.id)" ng-if="folderStatus(folder) == 'outofsync' && folder.type = 'readonly'">
|
||||||
<span class="fa fa-arrow-circle-up"></span> <span translate>Override Changes</span>
|
<span class="fa fa-arrow-circle-up"></span> <span translate>Override Changes</span>
|
||||||
</button>
|
</button>
|
||||||
<span class="pull-right">
|
<span class="pull-right">
|
||||||
|
@ -1201,6 +1201,7 @@ angular.module('syncthing.core')
|
|||||||
$scope.currentFolder = {
|
$scope.currentFolder = {
|
||||||
selectedDevices: {},
|
selectedDevices: {},
|
||||||
id: $scope.createRandomFolderId(),
|
id: $scope.createRandomFolderId(),
|
||||||
|
type: "readwrite",
|
||||||
rescanIntervalS: 60,
|
rescanIntervalS: 60,
|
||||||
minDiskFreePct: 1,
|
minDiskFreePct: 1,
|
||||||
maxConflicts: 10,
|
maxConflicts: 10,
|
||||||
|
@ -91,13 +91,13 @@
|
|||||||
<!-- Left column -->
|
<!-- Left column -->
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox">
|
<label translate>Folder Type</label>
|
||||||
<label>
|
|
||||||
<input type="checkbox" ng-model="currentFolder.readOnly"> <span translate>Folder Master</span>
|
|
||||||
</label>
|
|
||||||
<a href="http://docs.syncthing.net/users/foldermaster.html" target="_blank"><span class="fa fa-book"></span> <span translate>Help</span></a>
|
<a href="http://docs.syncthing.net/users/foldermaster.html" target="_blank"><span class="fa fa-book"></span> <span translate>Help</span></a>
|
||||||
</div>
|
<select class="form-control" ng-model="currentFolder.type">
|
||||||
<p translate class="help-block">Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.</p>
|
<option value="readwrite" translate>Normal</option>
|
||||||
|
<option value="readonly" translate>Master</option>
|
||||||
|
</select>
|
||||||
|
<p ng-if="currentFolder.type == 'readonly'" translate class="help-block">Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
|
@ -23,6 +23,9 @@ const (
|
|||||||
OldestHandledVersion = 10
|
OldestHandledVersion = 10
|
||||||
CurrentVersion = 13
|
CurrentVersion = 13
|
||||||
MaxRescanIntervalS = 365 * 24 * 60 * 60
|
MaxRescanIntervalS = 365 * 24 * 60 * 60
|
||||||
|
|
||||||
|
FolderTypeReadWrite = "readwrite"
|
||||||
|
FolderTypeReadOnly = "readonly"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -247,6 +250,15 @@ func convertV12V13(cfg *Configuration) {
|
|||||||
cfg.Options.NATRenewalM = cfg.Options.DeprecatedUPnPRenewalM
|
cfg.Options.NATRenewalM = cfg.Options.DeprecatedUPnPRenewalM
|
||||||
cfg.Options.NATTimeoutS = cfg.Options.DeprecatedUPnPTimeoutS
|
cfg.Options.NATTimeoutS = cfg.Options.DeprecatedUPnPTimeoutS
|
||||||
cfg.Version = 13
|
cfg.Version = 13
|
||||||
|
|
||||||
|
for i, fcfg := range cfg.Folders {
|
||||||
|
if fcfg.DeprecatedReadOnly {
|
||||||
|
cfg.Folders[i].Type = FolderTypeReadOnly
|
||||||
|
} else {
|
||||||
|
cfg.Folders[i].Type = FolderTypeReadWrite
|
||||||
|
}
|
||||||
|
cfg.Folders[i].DeprecatedReadOnly = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertV11V12(cfg *Configuration) {
|
func convertV11V12(cfg *Configuration) {
|
||||||
|
@ -94,7 +94,7 @@ func TestDeviceConfig(t *testing.T) {
|
|||||||
ID: "test",
|
ID: "test",
|
||||||
RawPath: "testdata",
|
RawPath: "testdata",
|
||||||
Devices: []FolderDeviceConfiguration{{DeviceID: device1}, {DeviceID: device4}},
|
Devices: []FolderDeviceConfiguration{{DeviceID: device1}, {DeviceID: device4}},
|
||||||
ReadOnly: true,
|
Type: FolderTypeReadOnly,
|
||||||
RescanIntervalS: 600,
|
RescanIntervalS: 600,
|
||||||
Copiers: 0,
|
Copiers: 0,
|
||||||
Pullers: 0,
|
Pullers: 0,
|
||||||
|
@ -20,8 +20,8 @@ type FolderConfiguration struct {
|
|||||||
ID string `xml:"id,attr" json:"id"`
|
ID string `xml:"id,attr" json:"id"`
|
||||||
Label string `xml:"label,attr" json:"label"`
|
Label string `xml:"label,attr" json:"label"`
|
||||||
RawPath string `xml:"path,attr" json:"path"`
|
RawPath string `xml:"path,attr" json:"path"`
|
||||||
|
Type string `xml:"type,attr" json:"type"`
|
||||||
Devices []FolderDeviceConfiguration `xml:"device" json:"devices"`
|
Devices []FolderDeviceConfiguration `xml:"device" json:"devices"`
|
||||||
ReadOnly bool `xml:"ro,attr" json:"readOnly"`
|
|
||||||
RescanIntervalS int `xml:"rescanIntervalS,attr" json:"rescanIntervalS"`
|
RescanIntervalS int `xml:"rescanIntervalS,attr" json:"rescanIntervalS"`
|
||||||
IgnorePerms bool `xml:"ignorePerms,attr" json:"ignorePerms"`
|
IgnorePerms bool `xml:"ignorePerms,attr" json:"ignorePerms"`
|
||||||
AutoNormalize bool `xml:"autoNormalize,attr" json:"autoNormalize"`
|
AutoNormalize bool `xml:"autoNormalize,attr" json:"autoNormalize"`
|
||||||
@ -41,16 +41,19 @@ type FolderConfiguration struct {
|
|||||||
|
|
||||||
Invalid string `xml:"-" json:"invalid"` // Set at runtime when there is an error, not saved
|
Invalid string `xml:"-" json:"invalid"` // Set at runtime when there is an error, not saved
|
||||||
cachedPath string
|
cachedPath string
|
||||||
|
|
||||||
|
DeprecatedReadOnly bool `xml:"ro,attr" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FolderDeviceConfiguration struct {
|
type FolderDeviceConfiguration struct {
|
||||||
DeviceID protocol.DeviceID `xml:"id,attr" json:"deviceID"`
|
DeviceID protocol.DeviceID `xml:"id,attr" json:"deviceID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFolderConfiguration(id, path string) FolderConfiguration {
|
func NewFolderConfiguration(id, path, foldertype string) FolderConfiguration {
|
||||||
f := FolderConfiguration{
|
f := FolderConfiguration{
|
||||||
ID: id,
|
ID: id,
|
||||||
RawPath: path,
|
RawPath: path,
|
||||||
|
Type: foldertype,
|
||||||
}
|
}
|
||||||
f.prepare()
|
f.prepare()
|
||||||
return f
|
return f
|
||||||
|
2
lib/config/testdata/v13.xml
vendored
2
lib/config/testdata/v13.xml
vendored
@ -1,5 +1,5 @@
|
|||||||
<configuration version="13">
|
<configuration version="13">
|
||||||
<folder id="test" path="testdata" ro="true" ignorePerms="false" rescanIntervalS="600" autoNormalize="true">
|
<folder id="test" path="testdata" type="readonly" ignorePerms="false" rescanIntervalS="600" autoNormalize="true">
|
||||||
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR"></device>
|
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR"></device>
|
||||||
<device id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2"></device>
|
<device id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2"></device>
|
||||||
<minDiskFreePct>1</minDiskFreePct>
|
<minDiskFreePct>1</minDiskFreePct>
|
||||||
|
@ -100,8 +100,11 @@ type Model struct {
|
|||||||
pmut sync.RWMutex // protects the above
|
pmut sync.RWMutex // protects the above
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type folderFactory func(*Model, config.FolderConfiguration, versioner.Versioner) service
|
||||||
|
|
||||||
var (
|
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,
|
// 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)
|
deadlockDetect(m.pmut, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartFolderRW starts read/write processing on the current model. When in
|
// StartFolder constrcuts the folder service and starts it.
|
||||||
// read/write mode the model will attempt to keep in sync with the cluster by
|
func (m *Model) StartFolder(folder string) {
|
||||||
// pulling needed files from peer devices.
|
|
||||||
func (m *Model) StartFolderRW(folder string) {
|
|
||||||
m.fmut.Lock()
|
m.fmut.Lock()
|
||||||
cfg, ok := m.folderCfgs[folder]
|
cfg, ok := m.folderCfgs[folder]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -172,37 +173,43 @@ func (m *Model) StartFolderRW(folder string) {
|
|||||||
if ok {
|
if ok {
|
||||||
panic("cannot start already running folder " + folder)
|
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 {
|
if len(cfg.Versioning.Type) > 0 {
|
||||||
factory, ok := versioner.Factories[cfg.Versioning.Type]
|
versionerFactory, ok := versioner.Factories[cfg.Versioning.Type]
|
||||||
if !ok {
|
if !ok {
|
||||||
l.Fatalf("Requested versioning type %q that does not exist", cfg.Versioning.Type)
|
l.Fatalf("Requested versioning type %q that does not exist", cfg.Versioning.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
versioner := factory(folder, cfg.Path(), cfg.Versioning.Params)
|
ver = versionerFactory(folder, cfg.Path(), cfg.Versioning.Params)
|
||||||
if service, ok := versioner.(suture.Service); ok {
|
if service, ok := ver.(suture.Service); ok {
|
||||||
// The versioner implements the suture.Service interface, so
|
// The versioner implements the suture.Service interface, so
|
||||||
// expects to be run in the background in addition to being called
|
// expects to be run in the background in addition to being called
|
||||||
// when files are going to be archived.
|
// when files are going to be archived.
|
||||||
token := m.Add(service)
|
token := m.Add(service)
|
||||||
m.folderRunnerTokens[folder] = append(m.folderRunnerTokens[folder], token)
|
m.folderRunnerTokens[folder] = append(m.folderRunnerTokens[folder], token)
|
||||||
}
|
}
|
||||||
p.versioner = versioner
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p := folderFactory(m, cfg, ver)
|
||||||
|
m.folderRunners[folder] = p
|
||||||
|
|
||||||
m.warnAboutOverwritingProtectedFiles(folder)
|
m.warnAboutOverwritingProtectedFiles(folder)
|
||||||
|
|
||||||
token := m.Add(p)
|
token := m.Add(p)
|
||||||
m.folderRunnerTokens[folder] = append(m.folderRunnerTokens[folder], token)
|
m.folderRunnerTokens[folder] = append(m.folderRunnerTokens[folder], token)
|
||||||
m.fmut.Unlock()
|
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) {
|
func (m *Model) warnAboutOverwritingProtectedFiles(folder string) {
|
||||||
if m.folderCfgs[folder].ReadOnly {
|
if m.folderCfgs[folder].Type == config.FolderTypeReadOnly {
|
||||||
return
|
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) {
|
func (m *Model) RemoveFolder(folder string) {
|
||||||
m.fmut.Lock()
|
m.fmut.Lock()
|
||||||
m.pmut.Lock()
|
m.pmut.Lock()
|
||||||
@ -1093,7 +1076,7 @@ func (m *Model) DownloadProgress(device protocol.DeviceID, folder string, update
|
|||||||
cfg, ok := m.folderCfgs[folder]
|
cfg, ok := m.folderCfgs[folder]
|
||||||
m.fmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
if !ok || cfg.ReadOnly || cfg.DisableTempIndexes {
|
if !ok || cfg.Type == config.FolderTypeReadOnly || cfg.DisableTempIndexes {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1606,7 +1589,7 @@ func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster
|
|||||||
Label: folderCfg.Label,
|
Label: folderCfg.Label,
|
||||||
}
|
}
|
||||||
var flags uint32
|
var flags uint32
|
||||||
if folderCfg.ReadOnly {
|
if folderCfg.Type == config.FolderTypeReadOnly {
|
||||||
flags |= protocol.FlagFolderReadOnly
|
flags |= protocol.FlagFolderReadOnly
|
||||||
}
|
}
|
||||||
if folderCfg.IgnorePerms {
|
if folderCfg.IgnorePerms {
|
||||||
@ -1874,7 +1857,7 @@ func (m *Model) CheckFolderHealth(id string) error {
|
|||||||
case !folder.HasMarker():
|
case !folder.HasMarker():
|
||||||
err = errors.New("folder marker missing")
|
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
|
// 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
|
// going to change the contents of master folders, so we don't
|
||||||
// care about the amount of free space there.
|
// 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.
|
// A folder was added.
|
||||||
l.Debugln(m, "adding folder", folderID)
|
l.Debugln(m, "adding folder", folderID)
|
||||||
m.AddFolder(cfg)
|
m.AddFolder(cfg)
|
||||||
if cfg.ReadOnly {
|
m.StartFolder(folderID)
|
||||||
m.StartFolderRO(folderID)
|
|
||||||
} else {
|
|
||||||
m.StartFolderRW(folderID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drop connections to all devices that can now share the new
|
// Drop connections to all devices that can now share the new
|
||||||
// folder.
|
// folder.
|
||||||
|
@ -34,7 +34,7 @@ func init() {
|
|||||||
device1, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
|
device1, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
|
||||||
device2, _ = protocol.DeviceIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY")
|
device2, _ = protocol.DeviceIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY")
|
||||||
|
|
||||||
defaultFolderConfig = config.NewFolderConfiguration("default", "testdata")
|
defaultFolderConfig = config.NewFolderConfiguration("default", "testdata", config.FolderTypeReadWrite)
|
||||||
defaultFolderConfig.Devices = []config.FolderDeviceConfiguration{{DeviceID: device1}}
|
defaultFolderConfig.Devices = []config.FolderDeviceConfiguration{{DeviceID: device1}}
|
||||||
_defaultConfig := config.Configuration{
|
_defaultConfig := config.Configuration{
|
||||||
Folders: []config.FolderConfiguration{defaultFolderConfig},
|
Folders: []config.FolderConfiguration{defaultFolderConfig},
|
||||||
@ -85,7 +85,7 @@ func TestRequest(t *testing.T) {
|
|||||||
|
|
||||||
// device1 shares default, but device2 doesn't
|
// device1 shares default, but device2 doesn't
|
||||||
m.AddFolder(defaultFolderConfig)
|
m.AddFolder(defaultFolderConfig)
|
||||||
m.StartFolderRO("default")
|
m.StartFolder("default")
|
||||||
m.ServeBackground()
|
m.ServeBackground()
|
||||||
m.ScanFolder("default")
|
m.ScanFolder("default")
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ func benchmarkIndex(b *testing.B, nfiles int) {
|
|||||||
db := db.OpenMemory()
|
db := db.OpenMemory()
|
||||||
m := NewModel(defaultConfig, protocol.LocalDeviceID, "device", "syncthing", "dev", db, nil)
|
m := NewModel(defaultConfig, protocol.LocalDeviceID, "device", "syncthing", "dev", db, nil)
|
||||||
m.AddFolder(defaultFolderConfig)
|
m.AddFolder(defaultFolderConfig)
|
||||||
m.StartFolderRO("default")
|
m.StartFolder("default")
|
||||||
m.ServeBackground()
|
m.ServeBackground()
|
||||||
|
|
||||||
files := genFiles(nfiles)
|
files := genFiles(nfiles)
|
||||||
@ -188,7 +188,7 @@ func benchmarkIndexUpdate(b *testing.B, nfiles, nufiles int) {
|
|||||||
db := db.OpenMemory()
|
db := db.OpenMemory()
|
||||||
m := NewModel(defaultConfig, protocol.LocalDeviceID, "device", "syncthing", "dev", db, nil)
|
m := NewModel(defaultConfig, protocol.LocalDeviceID, "device", "syncthing", "dev", db, nil)
|
||||||
m.AddFolder(defaultFolderConfig)
|
m.AddFolder(defaultFolderConfig)
|
||||||
m.StartFolderRO("default")
|
m.StartFolder("default")
|
||||||
m.ServeBackground()
|
m.ServeBackground()
|
||||||
|
|
||||||
files := genFiles(nfiles)
|
files := genFiles(nfiles)
|
||||||
@ -492,7 +492,7 @@ func TestIgnores(t *testing.T) {
|
|||||||
db := db.OpenMemory()
|
db := db.OpenMemory()
|
||||||
m := NewModel(defaultConfig, protocol.LocalDeviceID, "device", "syncthing", "dev", db, nil)
|
m := NewModel(defaultConfig, protocol.LocalDeviceID, "device", "syncthing", "dev", db, nil)
|
||||||
m.AddFolder(defaultFolderConfig)
|
m.AddFolder(defaultFolderConfig)
|
||||||
m.StartFolderRO("default")
|
m.StartFolder("default")
|
||||||
m.ServeBackground()
|
m.ServeBackground()
|
||||||
|
|
||||||
expected := []string{
|
expected := []string{
|
||||||
@ -609,6 +609,7 @@ func TestROScanRecovery(t *testing.T) {
|
|||||||
fcfg := config.FolderConfiguration{
|
fcfg := config.FolderConfiguration{
|
||||||
ID: "default",
|
ID: "default",
|
||||||
RawPath: "testdata/rotestfolder",
|
RawPath: "testdata/rotestfolder",
|
||||||
|
Type: config.FolderTypeReadOnly,
|
||||||
RescanIntervalS: 1,
|
RescanIntervalS: 1,
|
||||||
}
|
}
|
||||||
cfg := config.Wrap("/tmp/test", config.Configuration{
|
cfg := config.Wrap("/tmp/test", config.Configuration{
|
||||||
@ -624,7 +625,7 @@ func TestROScanRecovery(t *testing.T) {
|
|||||||
|
|
||||||
m := NewModel(cfg, protocol.LocalDeviceID, "device", "syncthing", "dev", ldb, nil)
|
m := NewModel(cfg, protocol.LocalDeviceID, "device", "syncthing", "dev", ldb, nil)
|
||||||
m.AddFolder(fcfg)
|
m.AddFolder(fcfg)
|
||||||
m.StartFolderRO("default")
|
m.StartFolder("default")
|
||||||
m.ServeBackground()
|
m.ServeBackground()
|
||||||
|
|
||||||
waitFor := func(status string) error {
|
waitFor := func(status string) error {
|
||||||
@ -693,6 +694,7 @@ func TestRWScanRecovery(t *testing.T) {
|
|||||||
fcfg := config.FolderConfiguration{
|
fcfg := config.FolderConfiguration{
|
||||||
ID: "default",
|
ID: "default",
|
||||||
RawPath: "testdata/rwtestfolder",
|
RawPath: "testdata/rwtestfolder",
|
||||||
|
Type: config.FolderTypeReadWrite,
|
||||||
RescanIntervalS: 1,
|
RescanIntervalS: 1,
|
||||||
}
|
}
|
||||||
cfg := config.Wrap("/tmp/test", config.Configuration{
|
cfg := config.Wrap("/tmp/test", config.Configuration{
|
||||||
@ -708,7 +710,7 @@ func TestRWScanRecovery(t *testing.T) {
|
|||||||
|
|
||||||
m := NewModel(cfg, protocol.LocalDeviceID, "device", "syncthing", "dev", ldb, nil)
|
m := NewModel(cfg, protocol.LocalDeviceID, "device", "syncthing", "dev", ldb, nil)
|
||||||
m.AddFolder(fcfg)
|
m.AddFolder(fcfg)
|
||||||
m.StartFolderRW("default")
|
m.StartFolder("default")
|
||||||
m.ServeBackground()
|
m.ServeBackground()
|
||||||
|
|
||||||
waitFor := func(status string) error {
|
waitFor := func(status string) error {
|
||||||
@ -1219,7 +1221,7 @@ func TestIgnoreDelete(t *testing.T) {
|
|||||||
|
|
||||||
m.AddFolder(cfg)
|
m.AddFolder(cfg)
|
||||||
m.ServeBackground()
|
m.ServeBackground()
|
||||||
m.StartFolderRW("default")
|
m.StartFolder("default")
|
||||||
m.ScanFolder("default")
|
m.ScanFolder("default")
|
||||||
|
|
||||||
// Get a currently existing file
|
// Get a currently existing file
|
||||||
|
@ -12,13 +12,18 @@ import (
|
|||||||
|
|
||||||
"github.com/syncthing/syncthing/lib/config"
|
"github.com/syncthing/syncthing/lib/config"
|
||||||
"github.com/syncthing/syncthing/lib/sync"
|
"github.com/syncthing/syncthing/lib/sync"
|
||||||
|
"github.com/syncthing/syncthing/lib/versioner"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
folderFactories[config.FolderTypeReadOnly] = newROFolder
|
||||||
|
}
|
||||||
|
|
||||||
type roFolder struct {
|
type roFolder struct {
|
||||||
folder
|
folder
|
||||||
}
|
}
|
||||||
|
|
||||||
func newROFolder(model *Model, cfg config.FolderConfiguration) *roFolder {
|
func newROFolder(model *Model, cfg config.FolderConfiguration, ver versioner.Versioner) service {
|
||||||
return &roFolder{
|
return &roFolder{
|
||||||
folder: folder{
|
folder: folder{
|
||||||
stateTracker: stateTracker{
|
stateTracker: stateTracker{
|
||||||
|
@ -31,6 +31,10 @@ import (
|
|||||||
|
|
||||||
// TODO: Stop on errors
|
// TODO: Stop on errors
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
folderFactories[config.FolderTypeReadWrite] = newRWFolder
|
||||||
|
}
|
||||||
|
|
||||||
// A pullBlockState is passed to the puller routine for each block that needs
|
// A pullBlockState is passed to the puller routine for each block that needs
|
||||||
// to be fetched.
|
// to be fetched.
|
||||||
type pullBlockState struct {
|
type pullBlockState struct {
|
||||||
@ -98,7 +102,7 @@ type rwFolder struct {
|
|||||||
errorsMut sync.Mutex
|
errorsMut sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRWFolder(model *Model, cfg config.FolderConfiguration) *rwFolder {
|
func newRWFolder(model *Model, cfg config.FolderConfiguration, ver versioner.Versioner) service {
|
||||||
f := &rwFolder{
|
f := &rwFolder{
|
||||||
folder: folder{
|
folder: folder{
|
||||||
stateTracker: stateTracker{
|
stateTracker: stateTracker{
|
||||||
@ -124,6 +128,7 @@ func newRWFolder(model *Model, cfg config.FolderConfiguration) *rwFolder {
|
|||||||
maxConflicts: cfg.MaxConflicts,
|
maxConflicts: cfg.MaxConflicts,
|
||||||
allowSparse: !cfg.DisableSparseFiles,
|
allowSparse: !cfg.DisableSparseFiles,
|
||||||
checkFreeSpace: cfg.MinDiskFreePct != 0,
|
checkFreeSpace: cfg.MinDiskFreePct != 0,
|
||||||
|
versioner: ver,
|
||||||
|
|
||||||
queue: newJobQueue(),
|
queue: newJobQueue(),
|
||||||
pullTimer: time.NewTimer(time.Second),
|
pullTimer: time.NewTimer(time.Second),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user