all: Add folder pause, make pauses permanent (fixes #3407, fixes #215, fixes #3001)

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3520
This commit is contained in:
Audrius Butkevicius 2016-12-21 18:41:25 +00:00 committed by Jakob Borg
parent 0725e3af38
commit bab7c8ebbf
20 changed files with 548 additions and 307 deletions

View File

@ -82,8 +82,6 @@ type modelIntf interface {
Availability(folder, file string, version protocol.Vector, block protocol.BlockInfo) []model.Availability
GetIgnores(folder string) ([]string, []string, error)
SetIgnores(folder string, content []string) error
PauseDevice(device protocol.DeviceID)
ResumeDevice(device protocol.DeviceID)
DelayScan(folder string, next time.Duration)
ScanFolder(folder string) error
ScanFolders() map[string]error
@ -105,6 +103,7 @@ type configIntf interface {
Subscribe(c config.Committer)
Folders() map[string]config.FolderConfiguration
Devices() map[protocol.DeviceID]config.DeviceConfiguration
SetDevice(config.DeviceConfiguration) error
Save() error
ListenAddresses() []string
RequiresRestart() bool
@ -258,21 +257,21 @@ func (s *apiService) Serve() {
// The POST handlers
postRestMux := http.NewServeMux()
postRestMux.HandleFunc("/rest/db/prio", s.postDBPrio) // folder file [perpage] [page]
postRestMux.HandleFunc("/rest/db/ignores", s.postDBIgnores) // folder
postRestMux.HandleFunc("/rest/db/override", s.postDBOverride) // folder
postRestMux.HandleFunc("/rest/db/scan", s.postDBScan) // folder [sub...] [delay]
postRestMux.HandleFunc("/rest/system/config", s.postSystemConfig) // <body>
postRestMux.HandleFunc("/rest/system/error", s.postSystemError) // <body>
postRestMux.HandleFunc("/rest/system/error/clear", s.postSystemErrorClear) // -
postRestMux.HandleFunc("/rest/system/ping", s.restPing) // -
postRestMux.HandleFunc("/rest/system/reset", s.postSystemReset) // [folder]
postRestMux.HandleFunc("/rest/system/restart", s.postSystemRestart) // -
postRestMux.HandleFunc("/rest/system/shutdown", s.postSystemShutdown) // -
postRestMux.HandleFunc("/rest/system/upgrade", s.postSystemUpgrade) // -
postRestMux.HandleFunc("/rest/system/pause", s.postSystemPause) // device
postRestMux.HandleFunc("/rest/system/resume", s.postSystemResume) // device
postRestMux.HandleFunc("/rest/system/debug", s.postSystemDebug) // [enable] [disable]
postRestMux.HandleFunc("/rest/db/prio", s.postDBPrio) // folder file [perpage] [page]
postRestMux.HandleFunc("/rest/db/ignores", s.postDBIgnores) // folder
postRestMux.HandleFunc("/rest/db/override", s.postDBOverride) // folder
postRestMux.HandleFunc("/rest/db/scan", s.postDBScan) // folder [sub...] [delay]
postRestMux.HandleFunc("/rest/system/config", s.postSystemConfig) // <body>
postRestMux.HandleFunc("/rest/system/error", s.postSystemError) // <body>
postRestMux.HandleFunc("/rest/system/error/clear", s.postSystemErrorClear) // -
postRestMux.HandleFunc("/rest/system/ping", s.restPing) // -
postRestMux.HandleFunc("/rest/system/reset", s.postSystemReset) // [folder]
postRestMux.HandleFunc("/rest/system/restart", s.postSystemRestart) // -
postRestMux.HandleFunc("/rest/system/shutdown", s.postSystemShutdown) // -
postRestMux.HandleFunc("/rest/system/upgrade", s.postSystemUpgrade) // -
postRestMux.HandleFunc("/rest/system/pause", s.makeDevicePauseHandler(true)) // device
postRestMux.HandleFunc("/rest/system/resume", s.makeDevicePauseHandler(false)) // device
postRestMux.HandleFunc("/rest/system/debug", s.postSystemDebug) // [enable] [disable]
// Debug endpoints, not for general use
debugMux := http.NewServeMux()
@ -1103,30 +1102,27 @@ func (s *apiService) postSystemUpgrade(w http.ResponseWriter, r *http.Request) {
}
}
func (s *apiService) postSystemPause(w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var deviceStr = qs.Get("device")
func (s *apiService) makeDevicePauseHandler(paused bool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var deviceStr = qs.Get("device")
device, err := protocol.DeviceIDFromString(deviceStr)
if err != nil {
http.Error(w, err.Error(), 500)
return
device, err := protocol.DeviceIDFromString(deviceStr)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
cfg, ok := s.cfg.Devices()[device]
if !ok {
http.Error(w, "not found", http.StatusNotFound)
}
cfg.Paused = paused
if err := s.cfg.SetDevice(cfg); err != nil {
http.Error(w, err.Error(), 500)
}
}
s.model.PauseDevice(device)
}
func (s *apiService) postSystemResume(w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var deviceStr = qs.Get("device")
device, err := protocol.DeviceIDFromString(deviceStr)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
s.model.ResumeDevice(device)
}
func (s *apiService) postDBScan(w http.ResponseWriter, r *http.Request) {

View File

@ -212,6 +212,7 @@ type RuntimeOptions struct {
auditEnabled bool
verbose bool
paused bool
unpaused bool
guiAddress string
guiAPIKey string
generateDir string
@ -267,7 +268,8 @@ func parseCommandLineOptions() RuntimeOptions {
flag.StringVar(&options.upgradeTo, "upgrade-to", options.upgradeTo, "Force upgrade directly from specified URL")
flag.BoolVar(&options.auditEnabled, "audit", false, "Write events to audit file")
flag.BoolVar(&options.verbose, "verbose", false, "Print verbose log output")
flag.BoolVar(&options.paused, "paused", false, "Start with all devices paused")
flag.BoolVar(&options.paused, "paused", false, "Start with all devices and folders paused")
flag.BoolVar(&options.unpaused, "unpaused", false, "Start with all devices and folders unpaused")
flag.StringVar(&options.logFile, "logfile", options.logFile, "Log file name (use \"-\" for stdout)")
if runtime.GOOS == "windows" {
// Allow user to hide the console window
@ -701,14 +703,17 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
m.StartDeadlockDetector(20 * time.Minute)
}
if runtimeOptions.paused {
for device := range cfg.Devices() {
m.PauseDevice(device)
}
if runtimeOptions.unpaused {
setPauseState(cfg, false)
} else if runtimeOptions.paused {
setPauseState(cfg, true)
}
// Add and start folders
for _, folderCfg := range cfg.Folders() {
if folderCfg.Paused {
continue
}
m.AddFolder(folderCfg)
m.StartFolder(folderCfg.ID)
}
@ -1203,3 +1208,16 @@ func showPaths() {
fmt.Printf("GUI override directory:\n\t%s\n\n", locations[locGUIAssets])
fmt.Printf("Default sync folder directory:\n\t%s\n\n", locations[locDefFolder])
}
func setPauseState(cfg *config.Wrapper, paused bool) {
raw := cfg.RawCopy()
for i := range raw.Devices {
raw.Devices[i].Paused = paused
}
for i := range raw.Folders {
raw.Folders[i].Paused = paused
}
if err := cfg.Replace(raw); err != nil {
l.Fatalln("Cannot adjust paused state:", err)
}
}

View File

@ -45,6 +45,10 @@ func (c *mockedConfig) Devices() map[protocol.DeviceID]config.DeviceConfiguratio
return nil
}
func (c *mockedConfig) SetDevice(config.DeviceConfiguration) error {
return nil
}
func (c *mockedConfig) Save() error {
return nil
}

View File

@ -166,6 +166,18 @@ func (s *verboseService) formatEvent(ev events.Event) string {
device := data["device"]
return fmt.Sprintf("Device %v was resumed", device)
case events.FolderPaused:
data := ev.Data.(map[string]string)
id := data["id"]
label := data["label"]
return fmt.Sprintf("Folder %v (%v) was paused", id, label)
case events.FolderResumed:
data := ev.Data.(map[string]string)
id := data["id"]
label := data["label"]
return fmt.Sprintf("Folder %v (%v) was resumed", id, label)
case events.ListenAddressesChanged:
data := ev.Data.(map[string]interface{})
address := data["address"]

View File

@ -271,6 +271,7 @@
<span class="fa fa-fw" ng-class="[folder.type == 'readonly' ? 'fa-lock' : 'fa-folder']"></span>
</div>
<div class="panel-status pull-right text-{{folderClass(folder)}}" ng-switch="folderStatus(folder)">
<span ng-switch-when="paused"><span class="hidden-xs" translate>Paused</span><span class="visible-xs">&#9724;</span></span>
<span ng-switch-when="unknown"><span class="hidden-xs" translate>Unknown</span><span class="visible-xs">&#9724;</span></span>
<span ng-switch-when="unshared"><span class="hidden-xs" translate>Unshared</span><span class="visible-xs">&#9724;</span></span>
<span ng-switch-when="stopped"><span class="hidden-xs" translate>Stopped</span><span class="visible-xs">&#9724;</span></span>
@ -307,11 +308,11 @@
<span tooltip data-original-title="{{folder.path}}">{{folder.path}}</span>
</td>
</tr>
<tr ng-if="model[folder.id].invalid || model[folder.id].error">
<tr ng-if="!folder.paused && (model[folder.id].invalid || model[folder.id].error)">
<th><span class="fa fa-fw fa-exclamation-triangle"></span>&nbsp;<span translate>Error</span></th>
<td class="text-right">{{model[folder.id].invalid || model[folder.id].error}}</td>
</tr>
<tr>
<tr ng-if="!folder.paused">
<th><span class="fa fa-fw fa-globe"></span>&nbsp;<span translate>Global State</span></th>
<td class="text-right">
<span tooltip data-original-title="{{model[folder.id].globalFiles | alwaysNumber}} {{'files' | translate}}, {{model[folder.id].globalDirectories | alwaysNumber}} {{'directories' | translate}}, ~{{model[folder.id].globalBytes | binary}}B">
@ -321,7 +322,7 @@
</span>
</td>
</tr>
<tr>
<tr ng-if="!folder.paused">
<th><span class="fa fa-fw fa-home"></span>&nbsp;<span translate>Local State</span></th>
<td class="text-right">
<span tooltip data-original-title="{{model[folder.id].localFiles | alwaysNumber}} {{'files' | translate}}, {{model[folder.id].localDirectories | alwaysNumber}} {{'directories' | translate}}, ~{{model[folder.id].localBytes | binary}}B">
@ -417,6 +418,12 @@
<span class="fa fa-arrow-circle-up"></span>&nbsp;<span translate>Override Changes</span>
</button>
<span class="pull-right">
<button ng-if="!folder.paused" type="button" class="btn btn-sm btn-default" ng-click="setFolderPause(folder.id, true)">
<span class="fa fa-pause"></span>&nbsp;<span translate>Pause</span>
</button>
<button ng-if="folder.paused" type="button" class="btn btn-sm btn-default" ng-click="setFolderPause(folder.id, false)">
<span class="fa fa-play"></span>&nbsp;<span translate>Resume</span>
</button>
<button type="button" class="btn btn-sm btn-default" ng-click="rescanFolder(folder.id)" ng-show="['idle', 'stopped', 'unshared'].indexOf(folderStatus(folder)) > -1">
<span class="fa fa-refresh"></span>&nbsp;<span translate>Rescan</span>
</button>
@ -601,10 +608,10 @@
</div>
<div class="panel-footer">
<span class="pull-right">
<button ng-if="!connections[deviceCfg.deviceID].paused" type="button" class="btn btn-sm btn-default" ng-click="pauseDevice(deviceCfg.deviceID)">
<button ng-if="!deviceCfg.paused" type="button" class="btn btn-sm btn-default" ng-click="setDevicePause(deviceCfg.deviceID, true)">
<span class="fa fa-pause"></span>&nbsp;<span translate>Pause</span>
</button>
<button ng-if="connections[deviceCfg.deviceID].paused" type="button" class="btn btn-sm btn-default" ng-click="resumeDevice(deviceCfg.deviceID)">
<button ng-if="deviceCfg.paused" type="button" class="btn btn-sm btn-default" ng-click="setDevicePause(deviceCfg.deviceID, false)">
<span class="fa fa-play"></span>&nbsp;<span translate>Resume</span>
</button>
<button type="button" class="btn btn-sm btn-default" ng-click="editDevice(deviceCfg)">

View File

@ -77,6 +77,8 @@ angular.module('syncthing.core')
STATE_CHANGED: 'StateChanged', // Emitted when a folder changes state
FOLDER_ERRORS: 'FolderErrors', // Emitted when a folder has errors preventing a full sync
FOLDER_SCAN_PROGRESS: 'FolderScanProgress', // Emitted every ScanProgressIntervalS seconds, indicating how far into the scan it is at.
FOLDER_PAUSED: 'FolderPaused', // Emitted when a folder is paused
FOLDER_RESUMED: 'FolderResumed', // Emitted when a folder is resumed
start: function() {
$http.get(urlbase + '/events?limit=1')

View File

@ -235,14 +235,6 @@ angular.module('syncthing.core')
$scope.deviceRejections[arg.data.device] = arg;
});
$scope.$on(Events.DEVICE_PAUSED, function (event, arg) {
$scope.connections[arg.data.device].paused = true;
});
$scope.$on(Events.DEVICE_RESUMED, function (event, arg) {
$scope.connections[arg.data.device].paused = false;
});
$scope.$on(Events.FOLDER_REJECTED, function (event, arg) {
$scope.folderRejections[arg.data.folder + "-" + arg.data.device] = arg;
});
@ -652,6 +644,10 @@ angular.module('syncthing.core')
return 'unknown';
}
if (folderCfg.paused) {
return 'paused';
}
// after restart syncthing process state may be empty
if (!$scope.model[folderCfg.id].state) {
return 'unknown';
@ -685,6 +681,9 @@ angular.module('syncthing.core')
if (status === 'idle') {
return 'success';
}
if (status == 'paused') {
return 'default';
}
if (status === 'syncing' || status === 'scanning') {
return 'primary';
}
@ -801,7 +800,7 @@ angular.module('syncthing.core')
return 'unknown';
}
if ($scope.connections[deviceCfg.deviceID].paused) {
if (deviceCfg.paused) {
return 'paused';
}
@ -827,7 +826,7 @@ angular.module('syncthing.core')
return 'info';
}
if ($scope.connections[deviceCfg.deviceID].paused) {
if (deviceCfg.paused) {
return 'default';
}
@ -964,12 +963,23 @@ angular.module('syncthing.core')
return device.deviceID.substr(0, 6);
};
$scope.pauseDevice = function (device) {
$http.post(urlbase + "/system/pause?device=" + device);
$scope.setDevicePause = function (device, pause) {
$scope.devices.forEach(function (cfg) {
if (cfg.deviceID == device) {
cfg.paused = pause;
}
});
$scope.config.devices = $scope.devices;
$scope.saveConfig();
};
$scope.resumeDevice = function (device) {
$http.post(urlbase + "/system/resume?device=" + device);
$scope.setFolderPause = function (folder, pause) {
var cfg = $scope.folders[folder];
if (cfg) {
cfg.paused = pause;
$scope.config.folders = folderList($scope.folders);
$scope.saveConfig();
}
};
$scope.editSettings = function () {

View File

@ -17,6 +17,7 @@ type DeviceConfiguration struct {
Introducer bool `xml:"introducer,attr" json:"introducer"`
SkipIntroductionRemovals bool `xml:"skipIntroductionRemovals,attr" json:"skipIntroductionRemovals"`
IntroducedBy protocol.DeviceID `xml:"introducedBy,attr" json:"introducedBy"`
Paused bool `xml:"paused" json:"paused"`
}
func NewDeviceConfiguration(id protocol.DeviceID, name string) DeviceConfiguration {

View File

@ -41,6 +41,7 @@ type FolderConfiguration struct {
DisableTempIndexes bool `xml:"disableTempIndexes" json:"disableTempIndexes"`
Fsync bool `xml:"fsync" json:"fsync"`
DisableWeakHash bool `xml:"disableWeakHash" json:"disableWeakHash"`
Paused bool `xml:"paused" json:"paused"`
cachedPath string

View File

@ -323,6 +323,18 @@ func (w *Wrapper) Device(id protocol.DeviceID) (DeviceConfiguration, bool) {
return DeviceConfiguration{}, false
}
// Folder returns the configuration for the given folder and an "ok" bool.
func (w *Wrapper) Folder(id string) (FolderConfiguration, bool) {
w.mut.Lock()
defer w.mut.Unlock()
for _, folder := range w.cfg.Folders {
if folder.ID == id {
return folder, true
}
}
return FolderConfiguration{}, false
}
// Save writes the configuration to disk, and generates a ConfigSaved event.
func (w *Wrapper) Save() error {
fd, err := osutil.CreateAtomic(w.path)

View File

@ -343,8 +343,7 @@ func (s *Service) connect() {
continue
}
paused := s.model.IsPaused(deviceID)
if paused {
if deviceCfg.Paused {
continue
}

View File

@ -116,7 +116,6 @@ type Model interface {
protocol.Model
AddConnection(conn Connection, hello protocol.HelloResult)
ConnectedTo(remoteID protocol.DeviceID) bool
IsPaused(remoteID protocol.DeviceID) bool
OnHello(protocol.DeviceID, net.Addr, protocol.HelloResult) error
GetHello(protocol.DeviceID) protocol.HelloIntf
}

View File

@ -982,33 +982,33 @@ var (
)
var fileDescriptorStructs = []byte{
// 446 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x51, 0xd1, 0x8a, 0xd3, 0x40,
0x14, 0xed, 0x6c, 0xb3, 0xdb, 0xf6, 0xc6, 0xae, 0xee, 0x20, 0xcb, 0x50, 0x30, 0x0d, 0x05, 0x21,
0x08, 0xa6, 0x5a, 0xf1, 0xc5, 0xc7, 0x7d, 0x58, 0x10, 0x44, 0x24, 0x2e, 0xeb, 0x63, 0x69, 0x32,
0xb7, 0xd9, 0xc1, 0x64, 0x26, 0x66, 0x26, 0x85, 0xfa, 0x25, 0xbe, 0xb9, 0x9f, 0xd3, 0x47, 0xbf,
0x40, 0xb4, 0xfe, 0x88, 0x74, 0x92, 0xc6, 0x3c, 0xfa, 0x76, 0xce, 0xbd, 0xe7, 0xdc, 0x7b, 0x66,
0x2e, 0x8c, 0xb5, 0x29, 0xab, 0xc4, 0xe8, 0xb0, 0x28, 0x95, 0x51, 0xf4, 0x84, 0xc7, 0x93, 0xe7,
0xa9, 0x30, 0x77, 0x55, 0x1c, 0x26, 0x2a, 0x9f, 0xa7, 0x2a, 0x55, 0x73, 0xdb, 0x8a, 0xab, 0xb5,
0x65, 0x96, 0x58, 0x54, 0x5b, 0x26, 0xaf, 0x3b, 0x72, 0xbd, 0x95, 0x89, 0xb9, 0x13, 0x32, 0xed,
0xa0, 0x4c, 0xc4, 0xf5, 0x84, 0x44, 0x65, 0xf3, 0x18, 0x8b, 0xda, 0x36, 0xfb, 0x04, 0xee, 0xb5,
0xc8, 0xf0, 0x16, 0x4b, 0x2d, 0x94, 0xa4, 0x2f, 0x60, 0xb0, 0xa9, 0x21, 0x23, 0x3e, 0x09, 0xdc,
0xc5, 0xa3, 0xf0, 0x68, 0x0a, 0x6f, 0x31, 0x31, 0xaa, 0xbc, 0x72, 0x76, 0x3f, 0xa7, 0xbd, 0xe8,
0x28, 0xa3, 0x97, 0x70, 0xc6, 0x71, 0x23, 0x12, 0x64, 0x27, 0x3e, 0x09, 0x1e, 0x44, 0x0d, 0x9b,
0x5d, 0x83, 0xdb, 0x0c, 0x7d, 0x27, 0xb4, 0xa1, 0x2f, 0x61, 0xd8, 0x38, 0x34, 0x23, 0x7e, 0x3f,
0x70, 0x17, 0x0f, 0x43, 0x1e, 0x87, 0x9d, 0xdd, 0xcd, 0xe0, 0x56, 0xf6, 0xc6, 0xf9, 0x76, 0x3f,
0xed, 0xcd, 0xbe, 0xf7, 0xe1, 0xe2, 0xa0, 0x7a, 0x2b, 0xd7, 0xea, 0xa6, 0xac, 0x64, 0xb2, 0x32,
0xc8, 0x29, 0x05, 0x47, 0xae, 0x72, 0xb4, 0x21, 0x47, 0x91, 0xc5, 0xf4, 0x19, 0x38, 0x66, 0x5b,
0xd4, 0x39, 0xce, 0x17, 0x97, 0xff, 0x82, 0xb7, 0xf6, 0x6d, 0x81, 0x91, 0xd5, 0x1c, 0xfc, 0x5a,
0x7c, 0x45, 0xd6, 0xf7, 0x49, 0xd0, 0x8f, 0x2c, 0xa6, 0x3e, 0xb8, 0x05, 0x96, 0xb9, 0xd0, 0x75,
0x4a, 0xc7, 0x27, 0xc1, 0x38, 0xea, 0x96, 0xe8, 0x13, 0x80, 0x5c, 0x71, 0xb1, 0x16, 0xc8, 0x97,
0x9a, 0x9d, 0x5a, 0xef, 0xe8, 0x58, 0xf9, 0x48, 0x19, 0x0c, 0x38, 0x66, 0x68, 0x90, 0xb3, 0x33,
0x9f, 0x04, 0xc3, 0xe8, 0x48, 0x0f, 0x1d, 0x21, 0x37, 0xab, 0x4c, 0x70, 0x36, 0xa8, 0x3b, 0x0d,
0xa5, 0x4f, 0xe1, 0x5c, 0xaa, 0x65, 0x77, 0xef, 0xd0, 0x0a, 0xc6, 0x52, 0x7d, 0xe8, 0x6c, 0xee,
0xdc, 0x65, 0xf4, 0x7f, 0x77, 0x99, 0xc0, 0x50, 0xe3, 0x97, 0x0a, 0x65, 0x82, 0x0c, 0x6c, 0xd2,
0x96, 0xd3, 0x29, 0xb8, 0xed, 0x3b, 0xa4, 0x66, 0xae, 0x4f, 0x82, 0xd3, 0xa8, 0x7d, 0xda, 0x7b,
0x7d, 0x48, 0xa5, 0xb7, 0x79, 0x26, 0xe4, 0xe7, 0xa5, 0x59, 0x95, 0x29, 0x1a, 0x76, 0x61, 0x3f,
0x7a, 0xdc, 0x54, 0x6f, 0x6c, 0xb1, 0xbe, 0xd0, 0xd5, 0xe3, 0xdd, 0x6f, 0xaf, 0xb7, 0xdb, 0x7b,
0xe4, 0xc7, 0xde, 0x23, 0xbf, 0xf6, 0x5e, 0xef, 0xfe, 0x8f, 0x47, 0xe2, 0x33, 0x9b, 0xef, 0xd5,
0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb1, 0x2f, 0x12, 0xb6, 0xda, 0x02, 0x00, 0x00,
// 442 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x51, 0x5d, 0x8b, 0xd3, 0x40,
0x14, 0x6d, 0xb7, 0xd9, 0x7e, 0xdc, 0xd8, 0xd5, 0x1d, 0x64, 0x19, 0x0a, 0xb6, 0x4b, 0x41, 0x10,
0xc1, 0x54, 0x57, 0x7c, 0xf1, 0x71, 0x1f, 0x16, 0x04, 0x11, 0x19, 0x97, 0xf5, 0xb1, 0x34, 0x99,
0xdb, 0xec, 0x60, 0x32, 0x53, 0x33, 0x93, 0x42, 0xfd, 0x25, 0xbe, 0xb9, 0x3f, 0xa7, 0x8f, 0xfe,
0x02, 0xd1, 0xfa, 0x47, 0x9c, 0xce, 0xa4, 0x31, 0x8f, 0xfb, 0x10, 0xb8, 0xe7, 0x9e, 0x73, 0xee,
0x3d, 0x93, 0x0b, 0x43, 0x6d, 0x8a, 0x32, 0x31, 0x3a, 0x5a, 0x15, 0xca, 0x28, 0x72, 0xc4, 0xe3,
0xd1, 0x8b, 0x54, 0x98, 0xdb, 0x32, 0x8e, 0x12, 0x95, 0xcf, 0x52, 0x95, 0xaa, 0x99, 0xa3, 0xe2,
0x72, 0xe9, 0x90, 0x03, 0xae, 0xf2, 0x96, 0xd1, 0x9b, 0x86, 0x5c, 0x6f, 0x64, 0x62, 0x6e, 0x85,
0x4c, 0x1b, 0x55, 0x26, 0x62, 0x3f, 0x21, 0x51, 0xd9, 0x2c, 0xc6, 0x95, 0xb7, 0x4d, 0x3f, 0x43,
0x78, 0x25, 0x32, 0xbc, 0xc1, 0x42, 0x0b, 0x25, 0xc9, 0x4b, 0xe8, 0xad, 0x7d, 0x49, 0xdb, 0xe7,
0xed, 0x67, 0xe1, 0xc5, 0xa3, 0xe8, 0x60, 0x8a, 0x6e, 0x30, 0x31, 0xaa, 0xb8, 0x0c, 0xb6, 0xbf,
0x26, 0x2d, 0x76, 0x90, 0x91, 0x33, 0xe8, 0x72, 0x5c, 0x8b, 0x04, 0xe9, 0x91, 0x35, 0x3c, 0x60,
0x15, 0x9a, 0x5e, 0x41, 0x58, 0x0d, 0x7d, 0x2f, 0xb4, 0x21, 0xaf, 0xa0, 0x5f, 0x39, 0xb4, 0x9d,
0xdc, 0xb1, 0x93, 0x1f, 0x46, 0x3c, 0x8e, 0x1a, 0xbb, 0xab, 0xc1, 0xb5, 0xec, 0x6d, 0xf0, 0xfd,
0x6e, 0xd2, 0x9a, 0xfe, 0xe8, 0xc0, 0xe9, 0x5e, 0xf5, 0x4e, 0x2e, 0xd5, 0x75, 0x51, 0xca, 0x64,
0x61, 0x90, 0x13, 0x02, 0x81, 0x5c, 0xe4, 0xe8, 0x42, 0x0e, 0x98, 0xab, 0xc9, 0x73, 0x08, 0xcc,
0x66, 0xe5, 0x73, 0x9c, 0x5c, 0x9c, 0xfd, 0x0f, 0x5e, 0xdb, 0x2d, 0xcb, 0x9c, 0x66, 0xef, 0xd7,
0xe2, 0x1b, 0xd2, 0x8e, 0xd5, 0x76, 0x98, 0xab, 0xc9, 0x39, 0x84, 0x2b, 0x2c, 0x72, 0xa1, 0x7d,
0xca, 0xc0, 0x52, 0x43, 0xd6, 0x6c, 0x91, 0x27, 0x00, 0xb9, 0xe2, 0x62, 0x29, 0x90, 0xcf, 0x35,
0x3d, 0x76, 0xde, 0xc1, 0xa1, 0xf3, 0x89, 0x50, 0xe8, 0x71, 0xcc, 0xd0, 0xe6, 0xa3, 0x5d, 0xcb,
0xf5, 0xd9, 0x01, 0xee, 0x19, 0x21, 0xd7, 0x8b, 0x4c, 0x70, 0xda, 0xf3, 0x4c, 0x05, 0xc9, 0x53,
0x38, 0x91, 0x6a, 0xde, 0xdc, 0xdb, 0x77, 0x82, 0xa1, 0x54, 0x1f, 0x1b, 0x9b, 0x1b, 0x77, 0x19,
0xdc, 0xef, 0x2e, 0x23, 0xe8, 0x6b, 0xfc, 0x5a, 0xa2, 0xb4, 0x97, 0x01, 0x97, 0xb4, 0xc6, 0x64,
0x02, 0x61, 0xfd, 0x0e, 0xbb, 0x31, 0xb4, 0xf4, 0x31, 0xab, 0x9f, 0xf6, 0x41, 0xef, 0x53, 0xe9,
0x4d, 0x9e, 0x09, 0xf9, 0x65, 0x6e, 0x16, 0x45, 0x8a, 0x86, 0x9e, 0xba, 0x1f, 0x3d, 0xac, 0xba,
0xd7, 0xae, 0xe9, 0x2f, 0x74, 0xf9, 0x78, 0xfb, 0x67, 0xdc, 0xda, 0xee, 0xc6, 0xed, 0x9f, 0xf6,
0xfb, 0xbd, 0x1b, 0xb7, 0xee, 0xfe, 0x8e, 0xdb, 0x71, 0xd7, 0xe5, 0x7b, 0xfd, 0x2f, 0x00, 0x00,
0xff, 0xff, 0xb1, 0x2f, 0x12, 0xb6, 0xda, 0x02, 0x00, 0x00,
}

View File

@ -382,21 +382,20 @@ var (
)
var fileDescriptorLocal = []byte{
// 241 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x4c, 0x8e, 0x4f, 0x4e, 0x84, 0x30,
0x14, 0xc6, 0x29, 0x24, 0x66, 0xa6, 0x63, 0x5c, 0x10, 0x17, 0xc4, 0x98, 0x42, 0x5c, 0xb1, 0x11,
0x16, 0x7a, 0x01, 0x09, 0x9b, 0x6e, 0xb9, 0x80, 0x81, 0xb6, 0x32, 0x2f, 0xc1, 0x3e, 0x43, 0x61,
0x12, 0x6f, 0xe3, 0x05, 0xbc, 0x07, 0x4b, 0xd7, 0x2e, 0x1a, 0xad, 0x17, 0x31, 0xe9, 0x68, 0x86,
0xdd, 0xf7, 0xfd, 0xf2, 0x7b, 0x7f, 0xe8, 0x6e, 0x40, 0xd1, 0x0e, 0xc5, 0xcb, 0x88, 0x13, 0xc6,
0x1b, 0x09, 0x46, 0xe0, 0x41, 0x8d, 0x57, 0xb7, 0x3d, 0x4c, 0xfb, 0xb9, 0x2b, 0x04, 0x3e, 0x97,
0x3d, 0xf6, 0x58, 0x7a, 0xa1, 0x9b, 0x9f, 0x7c, 0xf3, 0xc5, 0xa7, 0xe3, 0xe0, 0xcd, 0x3b, 0xa1,
0x9b, 0x07, 0xad, 0x71, 0xd6, 0x42, 0xc5, 0x0d, 0x0d, 0x41, 0x26, 0x24, 0x23, 0xf9, 0x79, 0x55,
0x2d, 0x36, 0x0d, 0x3e, 0x6d, 0x7a, 0xbf, 0xda, 0x67, 0x5e, 0xb5, 0x98, 0xf6, 0xa0, 0xfb, 0x55,
0x1a, 0xa0, 0x3b, 0x9e, 0x10, 0x38, 0x14, 0xb5, 0x3a, 0x80, 0x50, 0xbc, 0x76, 0x36, 0x0d, 0x79,
0xdd, 0x84, 0x20, 0xe3, 0x6b, 0xba, 0x6d, 0xa5, 0x1c, 0x95, 0x31, 0xca, 0x24, 0x61, 0x16, 0xe5,
0xdb, 0xe6, 0x04, 0xe2, 0x92, 0xee, 0x40, 0x9b, 0xa9, 0xd5, 0x42, 0x3d, 0x82, 0x4c, 0xa2, 0x8c,
0xe4, 0x51, 0x75, 0xe1, 0x6c, 0x4a, 0xf9, 0x1f, 0xe6, 0x75, 0x43, 0xff, 0x15, 0x2e, 0xab, 0xcb,
0xe5, 0x9b, 0x05, 0x8b, 0x63, 0xe4, 0xc3, 0x31, 0xf2, 0xe5, 0x58, 0xf0, 0xf6, 0xc3, 0x48, 0x77,
0xe6, 0x3f, 0xb8, 0xfb, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xa4, 0x46, 0x4f, 0x13, 0x14, 0x01, 0x00,
0x00,
// 235 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0xc9, 0x4f, 0x4e,
0xcc, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x48, 0xc9, 0x2c, 0x4e, 0xce, 0x2f, 0x4b,
0x2d, 0x92, 0xd2, 0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf,
0x4f, 0xcf, 0xd7, 0x07, 0x2b, 0x48, 0x2a, 0x4d, 0x03, 0xf3, 0xc0, 0x1c, 0x30, 0x0b, 0xa2, 0x51,
0x69, 0x2d, 0x23, 0x17, 0x87, 0x63, 0x5e, 0x5e, 0x7e, 0x69, 0x5e, 0x72, 0xaa, 0x50, 0x10, 0x17,
0x53, 0x66, 0x8a, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x8f, 0x93, 0xd3, 0x89, 0x7b, 0xf2, 0x0c, 0xb7,
0xee, 0xc9, 0x9b, 0x20, 0x99, 0x57, 0x5c, 0x99, 0x97, 0x5c, 0x92, 0x91, 0x99, 0x97, 0x8e, 0xc4,
0xca, 0xc9, 0x4c, 0x82, 0x58, 0x91, 0x9c, 0x9f, 0xa3, 0xe7, 0x92, 0x5a, 0x96, 0x99, 0x9c, 0xea,
0xe9, 0xf2, 0xe8, 0x9e, 0x3c, 0x93, 0xa7, 0x4b, 0x10, 0xd0, 0x34, 0x21, 0x19, 0x2e, 0xce, 0xc4,
0x94, 0x94, 0xa2, 0xd4, 0xe2, 0xe2, 0xd4, 0x62, 0x09, 0x26, 0x05, 0x66, 0x0d, 0xce, 0x20, 0x84,
0x80, 0x90, 0x3e, 0x17, 0x77, 0x66, 0x5e, 0x71, 0x49, 0x22, 0xd0, 0xf6, 0x78, 0xa0, 0xd5, 0xcc,
0x40, 0xab, 0x99, 0x9d, 0xf8, 0x80, 0xda, 0xb9, 0x3c, 0xa1, 0xc2, 0x40, 0x63, 0xb8, 0x60, 0x4a,
0x3c, 0x53, 0x9c, 0x44, 0x4e, 0x3c, 0x94, 0x63, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0x02, 0x10, 0x3f,
0x78, 0x24, 0xc7, 0xb0, 0xe0, 0xb1, 0x1c, 0x63, 0x12, 0x1b, 0xd8, 0x05, 0xc6, 0x80, 0x00, 0x00,
0x00, 0xff, 0xff, 0xa4, 0x46, 0x4f, 0x13, 0x14, 0x01, 0x00, 0x00,
}

View File

@ -43,6 +43,8 @@ const (
FolderCompletion
FolderErrors
FolderScanProgress
FolderPaused
FolderResumed
ListenAddressesChanged
LoginAttempt
@ -101,6 +103,10 @@ func (t EventType) String() string {
return "DeviceResumed"
case FolderScanProgress:
return "FolderScanProgress"
case FolderPaused:
return "FolderPaused"
case FolderResumed:
return "FolderResumed"
case ListenAddressesChanged:
return "ListenAddressesChanged"
case LoginAttempt:

View File

@ -93,12 +93,12 @@ type Model struct {
folderStatRefs map[string]*stats.FolderStatisticsReference // folder -> statsRef
fmut sync.RWMutex // protects the above
conn map[protocol.DeviceID]connections.Connection
closed map[protocol.DeviceID]chan struct{}
helloMessages map[protocol.DeviceID]protocol.HelloResult
devicePaused map[protocol.DeviceID]bool
deviceDownloads map[protocol.DeviceID]*deviceDownloadState
pmut sync.RWMutex // protects the above
conn map[protocol.DeviceID]connections.Connection
closed map[protocol.DeviceID]chan struct{}
helloMessages map[protocol.DeviceID]protocol.HelloResult
deviceDownloads map[protocol.DeviceID]*deviceDownloadState
remotePausedFolders map[protocol.DeviceID][]string // deviceID -> folders
pmut sync.RWMutex // protects the above
}
type folderFactory func(*Model, config.FolderConfiguration, versioner.Versioner, *fs.MtimeFS) service
@ -134,33 +134,33 @@ func NewModel(cfg *config.Wrapper, id protocol.DeviceID, deviceName, clientName,
l.Debugln(line)
},
}),
cfg: cfg,
db: ldb,
finder: db.NewBlockFinder(ldb),
progressEmitter: NewProgressEmitter(cfg),
id: id,
shortID: id.Short(),
cacheIgnoredFiles: cfg.Options().CacheIgnoredFiles,
protectedFiles: protectedFiles,
deviceName: deviceName,
clientName: clientName,
clientVersion: clientVersion,
folderCfgs: make(map[string]config.FolderConfiguration),
folderFiles: make(map[string]*db.FileSet),
folderDevices: make(folderDeviceSet),
deviceFolders: make(map[protocol.DeviceID][]string),
deviceStatRefs: make(map[protocol.DeviceID]*stats.DeviceStatisticsReference),
folderIgnores: make(map[string]*ignore.Matcher),
folderRunners: make(map[string]service),
folderRunnerTokens: make(map[string][]suture.ServiceToken),
folderStatRefs: make(map[string]*stats.FolderStatisticsReference),
conn: make(map[protocol.DeviceID]connections.Connection),
closed: make(map[protocol.DeviceID]chan struct{}),
helloMessages: make(map[protocol.DeviceID]protocol.HelloResult),
devicePaused: make(map[protocol.DeviceID]bool),
deviceDownloads: make(map[protocol.DeviceID]*deviceDownloadState),
fmut: sync.NewRWMutex(),
pmut: sync.NewRWMutex(),
cfg: cfg,
db: ldb,
finder: db.NewBlockFinder(ldb),
progressEmitter: NewProgressEmitter(cfg),
id: id,
shortID: id.Short(),
cacheIgnoredFiles: cfg.Options().CacheIgnoredFiles,
protectedFiles: protectedFiles,
deviceName: deviceName,
clientName: clientName,
clientVersion: clientVersion,
folderCfgs: make(map[string]config.FolderConfiguration),
folderFiles: make(map[string]*db.FileSet),
folderDevices: make(folderDeviceSet),
deviceFolders: make(map[protocol.DeviceID][]string),
deviceStatRefs: make(map[protocol.DeviceID]*stats.DeviceStatisticsReference),
folderIgnores: make(map[string]*ignore.Matcher),
folderRunners: make(map[string]service),
folderRunnerTokens: make(map[string][]suture.ServiceToken),
folderStatRefs: make(map[string]*stats.FolderStatisticsReference),
conn: make(map[protocol.DeviceID]connections.Connection),
closed: make(map[protocol.DeviceID]chan struct{}),
helloMessages: make(map[protocol.DeviceID]protocol.HelloResult),
deviceDownloads: make(map[protocol.DeviceID]*deviceDownloadState),
remotePausedFolders: make(map[protocol.DeviceID][]string),
fmut: sync.NewRWMutex(),
pmut: sync.NewRWMutex(),
}
if cfg.Options().ProgressUpdateIntervalS > -1 {
go m.progressEmitter.Serve()
@ -183,8 +183,10 @@ func (m *Model) StartDeadlockDetector(timeout time.Duration) {
// StartFolder constructs the folder service and starts it.
func (m *Model) StartFolder(folder string) {
m.fmut.Lock()
m.pmut.Lock()
folderType := m.startFolderLocked(folder)
folderCfg := m.folderCfgs[folder]
m.pmut.Unlock()
m.fmut.Unlock()
l.Infof("Ready to synchronize %s (%s)", folderCfg.Description(), folderType)
@ -218,6 +220,11 @@ func (m *Model) startFolderLocked(folder string) config.FolderType {
}
}
// Close connections to affected devices
for _, id := range cfg.DeviceIDs() {
m.closeLocked(id)
}
v, ok := fs.Sequence(protocol.LocalDeviceID), true
indexHasFiles := ok && v > 0
if !indexHasFiles {
@ -366,13 +373,16 @@ func (m *Model) RestartFolder(cfg config.FolderConfiguration) {
m.pmut.Lock()
m.tearDownFolderLocked(cfg.ID)
m.addFolderLocked(cfg)
folderType := m.startFolderLocked(cfg.ID)
if !cfg.Paused {
m.addFolderLocked(cfg)
folderType := m.startFolderLocked(cfg.ID)
l.Infoln("Restarted folder", cfg.Description(), fmt.Sprintf("(%s)", folderType))
} else {
l.Infoln("Paused folder", cfg.Description())
}
m.pmut.Unlock()
m.fmut.Unlock()
l.Infoln("Restarted folder", cfg.ID, fmt.Sprintf("(%s)", folderType))
}
type ConnectionInfo struct {
@ -405,7 +415,7 @@ func (m *Model) ConnectionStats() map[string]interface{} {
res := make(map[string]interface{})
devs := m.cfg.Devices()
conns := make(map[string]ConnectionInfo, len(devs))
for device := range devs {
for device, deviceCfg := range devs {
hello := m.helloMessages[device]
versionString := hello.ClientVersion
if hello.ClientName != "syncthing" {
@ -413,7 +423,7 @@ func (m *Model) ConnectionStats() map[string]interface{} {
}
ci := ConnectionInfo{
ClientVersion: strings.TrimSpace(versionString),
Paused: m.devicePaused[device],
Paused: deviceCfg.Paused,
}
if conn, ok := m.conn[device]; ok {
ci.Type = conn.Type()
@ -783,7 +793,17 @@ func (m *Model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
}
m.fmut.Lock()
var paused []string
for _, folder := range cm.Folders {
if folder.Paused {
paused = append(paused, folder.ID)
continue
}
if cfg, ok := m.cfg.Folder(folder.ID); ok && cfg.Paused {
continue
}
if !m.folderSharedWithLocked(folder.ID, deviceID) {
events.Default.Log(events.FolderRejected, map[string]string{
"folder": folder.ID,
@ -871,6 +891,10 @@ func (m *Model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
go sendIndexes(conn, folder.ID, fs, m.folderIgnores[folder.ID], startSequence, dbLocation, dropSymlinks)
}
m.pmut.Lock()
m.remotePausedFolders[deviceID] = paused
m.pmut.Unlock()
// This breaks if we send multiple CM messages during the same connection.
if len(tempIndexFolders) > 0 {
m.pmut.RLock()
@ -1058,6 +1082,7 @@ func (m *Model) Closed(conn protocol.Connection, err error) {
delete(m.conn, device)
delete(m.helloMessages, device)
delete(m.deviceDownloads, device)
delete(m.remotePausedFolders, device)
closed := m.closed[device]
delete(m.closed, device)
m.pmut.Unlock()
@ -1070,6 +1095,24 @@ func (m *Model) Closed(conn protocol.Connection, err error) {
close(closed)
}
// close will close the underlying connection for a given device
func (m *Model) close(device protocol.DeviceID) {
m.pmut.Lock()
m.closeLocked(device)
m.pmut.Unlock()
}
// closeLocked will close the underlying connection for a given device
func (m *Model) closeLocked(device protocol.DeviceID) {
conn, ok := m.conn[device]
if !ok {
// There is no connection to close
return
}
closeRawConn(conn)
}
// 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, offset int64, hash []byte, fromTemporary bool, buf []byte) error {
@ -1257,16 +1300,15 @@ func (m *Model) SetIgnores(folder string, content []string) error {
// 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 {
if m.IsPaused(remoteID) {
return errDevicePaused
}
if m.cfg.IgnoredDevice(remoteID) {
return errDeviceIgnored
}
if _, ok := m.cfg.Device(remoteID); ok {
if cfg, ok := m.cfg.Device(remoteID); ok {
// The device exists
if cfg.Paused {
return errDevicePaused
}
return nil
}
@ -1349,17 +1391,6 @@ func (m *Model) AddConnection(conn connections.Connection, hello protocol.HelloR
m.deviceWasSeen(deviceID)
}
func (m *Model) PauseDevice(device protocol.DeviceID) {
m.pmut.Lock()
m.devicePaused[device] = true
conn, ok := m.conn[device]
m.pmut.Unlock()
if ok {
closeRawConn(conn)
}
events.Default.Log(events.DevicePaused, map[string]string{"device": device.String()})
}
func (m *Model) DownloadProgress(device protocol.DeviceID, folder string, updates []protocol.FileDownloadProgressUpdate) {
if !m.folderSharedWith(folder, device) {
return
@ -1385,20 +1416,6 @@ func (m *Model) DownloadProgress(device protocol.DeviceID, folder string, update
})
}
func (m *Model) ResumeDevice(device protocol.DeviceID) {
m.pmut.Lock()
m.devicePaused[device] = false
m.pmut.Unlock()
events.Default.Log(events.DeviceResumed, map[string]string{"device": device.String()})
}
func (m *Model) IsPaused(device protocol.DeviceID) bool {
m.pmut.Lock()
paused := m.devicePaused[device]
m.pmut.Unlock()
return paused
}
func (m *Model) deviceStatRef(deviceID protocol.DeviceID) *stats.DeviceStatisticsReference {
m.fmut.Lock()
defer m.fmut.Unlock()
@ -1983,6 +2000,7 @@ func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster
IgnorePermissions: folderCfg.IgnorePerms,
IgnoreDelete: folderCfg.IgnoreDelete,
DisableTempIndexes: folderCfg.DisableTempIndexes,
Paused: folderCfg.Paused,
}
// Devices are sorted, so we always get the same order.
@ -2192,7 +2210,13 @@ func (m *Model) Availability(folder, file string, version protocol.Vector, block
}
var availabilities []Availability
next:
for _, device := range fs.Availability(file) {
for _, pausedFolder := range m.remotePausedFolders[device] {
if pausedFolder == folder {
continue next
}
}
_, ok := m.conn[device]
if ok {
availabilities = append(availabilities, Availability{ID: device, FromTemporary: false})
@ -2350,16 +2374,6 @@ func (m *Model) CommitConfiguration(from, to config.Configuration) bool {
l.Debugln(m, "adding folder", folderID)
m.AddFolder(cfg)
m.StartFolder(folderID)
// Drop connections to all devices that can now share the new
// folder.
m.pmut.Lock()
for _, dev := range cfg.DeviceIDs() {
if conn, ok := m.conn[dev]; ok {
closeRawConn(conn)
}
}
m.pmut.Unlock()
}
}
@ -2381,6 +2395,15 @@ func (m *Model) CommitConfiguration(from, to config.Configuration) bool {
if !reflect.DeepEqual(fromCfgCopy, toCfgCopy) {
m.RestartFolder(toCfg)
}
// Emit the folder pause/resume event
if fromCfg.Paused != toCfg.Paused {
eventType := events.FolderResumed
if toCfg.Paused {
eventType = events.FolderPaused
}
events.Default.Log(eventType, map[string]string{"id": toCfg.ID, "label": toCfg.Label})
}
}
// Removing a device. We actually don't need to do anything.
@ -2390,6 +2413,24 @@ func (m *Model) CommitConfiguration(from, to config.Configuration) bool {
// At some point model.Close() will get called for that device which will
// clean residue device state that is not part of any folder.
// Pausing a device, unpausing is handled by the connection service.
fromDevices := mapDeviceConfigs(from.Devices)
toDevices := mapDeviceConfigs(to.Devices)
for deviceID, toCfg := range toDevices {
fromCfg, ok := fromDevices[deviceID]
if !ok || fromCfg.Paused == toCfg.Paused {
continue
}
if toCfg.Paused {
l.Infoln("Pausing", deviceID)
m.close(deviceID)
events.Default.Log(events.DevicePaused, map[string]string{"device": deviceID.String()})
} else {
events.Default.Log(events.DeviceResumed, map[string]string{"device": deviceID.String()})
}
}
// Some options don't require restart as those components handle it fine
// by themselves.
from.Options.URAccepted = to.Options.URAccepted
@ -2431,6 +2472,16 @@ func mapDevices(devices []protocol.DeviceID) map[protocol.DeviceID]struct{} {
return m
}
// mapDeviceConfigs returns a map of device ID to device configuration for the given
// slice of folder configurations.
func mapDeviceConfigs(devices []config.DeviceConfiguration) map[protocol.DeviceID]config.DeviceConfiguration {
m := make(map[protocol.DeviceID]config.DeviceConfiguration, len(devices))
for _, dev := range devices {
m[dev.DeviceID] = dev
}
return m
}
func symlinkInvalid(folder string, fi db.FileIntf) bool {
if !symlinks.Supported && fi.IsSymlink() && !fi.IsInvalid() && !fi.IsDeleted() {
symlinkWarning.Do(func() {

View File

@ -2198,6 +2198,97 @@ func TestIssue3829(t *testing.T) {
}
}
func TestNoRequestsFromPausedDevices(t *testing.T) {
dbi := db.OpenMemory()
fcfg := config.NewFolderConfiguration("default", "testdata")
fcfg.Devices = []config.FolderDeviceConfiguration{
{DeviceID: device1},
{DeviceID: device2},
}
cfg := config.Configuration{
Folders: []config.FolderConfiguration{fcfg},
Devices: []config.DeviceConfiguration{
config.NewDeviceConfiguration(device1, "device1"),
config.NewDeviceConfiguration(device2, "device2"),
},
Options: config.OptionsConfiguration{
// Don't remove temporaries directly on startup
KeepTemporariesH: 1,
},
}
wcfg := config.Wrap("/tmp/test", cfg)
m := NewModel(wcfg, protocol.LocalDeviceID, "device", "syncthing", "dev", dbi, nil)
m.AddFolder(fcfg)
m.StartFolder(fcfg.ID)
m.ServeBackground()
file := testDataExpected["foo"]
files := m.folderFiles["default"]
files.Update(device1, []protocol.FileInfo{file})
files.Update(device2, []protocol.FileInfo{file})
avail := m.Availability("default", file.Name, file.Version, file.Blocks[0])
if len(avail) != 0 {
t.Errorf("should not be available, no connections")
}
addFakeConn(m, device1)
addFakeConn(m, device2)
// !!! This is not what I'd expect to happen, as we don't even know if the peer has the original index !!!
avail = m.Availability("default", file.Name, file.Version, file.Blocks[0])
if len(avail) != 2 {
t.Errorf("should have two available")
}
cc := protocol.ClusterConfig{
Folders: []protocol.Folder{
{
ID: "default",
Devices: []protocol.Device{
{ID: device1},
{ID: device2},
},
},
},
}
m.ClusterConfig(device1, cc)
m.ClusterConfig(device2, cc)
avail = m.Availability("default", file.Name, file.Version, file.Blocks[0])
if len(avail) != 2 {
t.Errorf("should have two available")
}
m.Closed(&fakeConnection{id: device1}, errDeviceUnknown)
m.Closed(&fakeConnection{id: device2}, errDeviceUnknown)
avail = m.Availability("default", file.Name, file.Version, file.Blocks[0])
if len(avail) != 0 {
t.Errorf("should have no available")
}
// Test that remote paused folders are not used.
addFakeConn(m, device1)
addFakeConn(m, device2)
m.ClusterConfig(device1, cc)
ccp := cc
ccp.Folders[0].Paused = true
m.ClusterConfig(device1, ccp)
avail = m.Availability("default", file.Name, file.Version, file.Blocks[0])
if len(avail) != 1 {
t.Errorf("should have one available")
}
}
func TestRootedJoinedPath(t *testing.T) {
type testcase struct {
root string

View File

@ -246,6 +246,7 @@ type Folder struct {
IgnorePermissions bool `protobuf:"varint,4,opt,name=ignore_permissions,json=ignorePermissions,proto3" json:"ignore_permissions,omitempty"`
IgnoreDelete bool `protobuf:"varint,5,opt,name=ignore_delete,json=ignoreDelete,proto3" json:"ignore_delete,omitempty"`
DisableTempIndexes bool `protobuf:"varint,6,opt,name=disable_temp_indexes,json=disableTempIndexes,proto3" json:"disable_temp_indexes,omitempty"`
Paused bool `protobuf:"varint,7,opt,name=paused,proto3" json:"paused,omitempty"`
Devices []Device `protobuf:"bytes,16,rep,name=devices" json:"devices"`
}
@ -593,6 +594,16 @@ func (m *Folder) MarshalTo(data []byte) (int, error) {
}
i++
}
if m.Paused {
data[i] = 0x38
i++
if m.Paused {
data[i] = 1
} else {
data[i] = 0
}
i++
}
if len(m.Devices) > 0 {
for _, msg := range m.Devices {
data[i] = 0x82
@ -1306,6 +1317,9 @@ func (m *Folder) ProtoSize() (n int) {
if m.DisableTempIndexes {
n += 2
}
if m.Paused {
n += 2
}
if len(m.Devices) > 0 {
for _, e := range m.Devices {
l = e.ProtoSize()
@ -2065,6 +2079,26 @@ func (m *Folder) Unmarshal(data []byte) error {
}
}
m.DisableTempIndexes = bool(v != 0)
case 7:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Paused", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowBep
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
v |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Paused = bool(v != 0)
case 16:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Devices", wireType)
@ -4140,112 +4174,110 @@ var (
)
var fileDescriptorBep = []byte{
// 1700 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x56, 0x4f, 0x73, 0xdb, 0xc6,
0x15, 0x17, 0x48, 0xf0, 0xdf, 0x23, 0xa5, 0x40, 0x6b, 0x59, 0x41, 0x61, 0x85, 0x42, 0xe0, 0xb8,
0x55, 0x34, 0x8d, 0xe2, 0xc6, 0x69, 0x33, 0xd3, 0x69, 0x3b, 0x43, 0x91, 0x90, 0xcc, 0x09, 0x0d,
0xb2, 0x4b, 0xca, 0xae, 0x73, 0x28, 0x06, 0x24, 0x96, 0x14, 0x46, 0x20, 0x96, 0x05, 0x40, 0xd9,
0xea, 0x47, 0x60, 0xbf, 0x40, 0x2f, 0x9c, 0xc9, 0xb5, 0xf7, 0x7e, 0x08, 0xf7, 0x96, 0xc9, 0xb1,
0x07, 0x4f, 0xa3, 0x5e, 0x7a, 0xec, 0xa5, 0xf7, 0x0e, 0x76, 0x01, 0x10, 0x94, 0xe4, 0x8e, 0x0f,
0x3d, 0x71, 0xf7, 0xbd, 0xdf, 0xbe, 0xdd, 0xf7, 0x7b, 0xef, 0xf7, 0x08, 0xa8, 0x0c, 0xc9, 0xec,
0x68, 0xe6, 0xd3, 0x90, 0xa2, 0x32, 0xfb, 0x19, 0x51, 0x57, 0xf9, 0x6c, 0xe2, 0x84, 0xe7, 0xf3,
0xe1, 0xd1, 0x88, 0x4e, 0x3f, 0x9f, 0xd0, 0x09, 0xfd, 0x9c, 0x79, 0x86, 0xf3, 0x31, 0xdb, 0xb1,
0x0d, 0x5b, 0xf1, 0x83, 0xda, 0x0c, 0x0a, 0x4f, 0x89, 0xeb, 0x52, 0xb4, 0x0f, 0x55, 0x9b, 0x5c,
0x3a, 0x23, 0x62, 0x7a, 0xd6, 0x94, 0xc8, 0x82, 0x2a, 0x1c, 0x54, 0x30, 0x70, 0x93, 0x61, 0x4d,
0x49, 0x04, 0x18, 0xb9, 0x0e, 0xf1, 0x42, 0x0e, 0xc8, 0x71, 0x00, 0x37, 0x31, 0xc0, 0x23, 0xd8,
0x8a, 0x01, 0x97, 0xc4, 0x0f, 0x1c, 0xea, 0xc9, 0x79, 0x86, 0xd9, 0xe4, 0xd6, 0xe7, 0xdc, 0xa8,
0x05, 0x50, 0x7c, 0x4a, 0x2c, 0x9b, 0xf8, 0xe8, 0x53, 0x10, 0xc3, 0xab, 0x19, 0xbf, 0x6b, 0xeb,
0x8b, 0xfb, 0x47, 0x49, 0x0e, 0x47, 0xcf, 0x48, 0x10, 0x58, 0x13, 0x32, 0xb8, 0x9a, 0x11, 0xcc,
0x20, 0xe8, 0x37, 0x50, 0x1d, 0xd1, 0xe9, 0xcc, 0x27, 0x01, 0x0b, 0x9c, 0x63, 0x27, 0xf6, 0x6e,
0x9d, 0x68, 0xae, 0x30, 0x38, 0x7b, 0x40, 0x6b, 0xc0, 0x66, 0xd3, 0x9d, 0x07, 0x21, 0xf1, 0x9b,
0xd4, 0x1b, 0x3b, 0x13, 0xf4, 0x18, 0x4a, 0x63, 0xea, 0xda, 0xc4, 0x0f, 0x64, 0x41, 0xcd, 0x1f,
0x54, 0xbf, 0x90, 0x56, 0xc1, 0x4e, 0x98, 0xe3, 0x58, 0x7c, 0xf3, 0x76, 0x7f, 0x03, 0x27, 0x30,
0xed, 0x4f, 0x39, 0x28, 0x72, 0x0f, 0xda, 0x85, 0x9c, 0x63, 0x73, 0x8a, 0x8e, 0x8b, 0xd7, 0x6f,
0xf7, 0x73, 0xed, 0x16, 0xce, 0x39, 0x36, 0xda, 0x81, 0x82, 0x6b, 0x0d, 0x89, 0x1b, 0x93, 0xc3,
0x37, 0xe8, 0x01, 0x54, 0x7c, 0x62, 0xd9, 0x26, 0xf5, 0xdc, 0x2b, 0x46, 0x49, 0x19, 0x97, 0x23,
0x43, 0xd7, 0x73, 0xaf, 0xd0, 0x67, 0x80, 0x9c, 0x89, 0x47, 0x7d, 0x62, 0xce, 0x88, 0x3f, 0x75,
0xd8, 0x6b, 0x03, 0x59, 0x64, 0xa8, 0x6d, 0xee, 0xe9, 0xad, 0x1c, 0xe8, 0x21, 0x6c, 0xc6, 0x70,
0x9b, 0xb8, 0x24, 0x24, 0x72, 0x81, 0x21, 0x6b, 0xdc, 0xd8, 0x62, 0x36, 0xf4, 0x18, 0x76, 0x6c,
0x27, 0xb0, 0x86, 0x2e, 0x31, 0x43, 0x32, 0x9d, 0x99, 0x8e, 0x67, 0x93, 0xd7, 0x24, 0x90, 0x8b,
0x0c, 0x8b, 0x62, 0xdf, 0x80, 0x4c, 0x67, 0x6d, 0xee, 0x89, 0xd8, 0xe0, 0x95, 0x0e, 0x64, 0xe9,
0x26, 0x1b, 0x2d, 0xe6, 0x48, 0xd8, 0x88, 0x61, 0xda, 0xbf, 0x73, 0x50, 0xe4, 0x1e, 0xf4, 0xe3,
0x94, 0x8d, 0xda, 0xf1, 0x6e, 0x84, 0xfa, 0xfb, 0xdb, 0xfd, 0x32, 0xf7, 0xb5, 0x5b, 0x19, 0x76,
0x10, 0x88, 0x99, 0xce, 0x61, 0x6b, 0xb4, 0x07, 0x15, 0xcb, 0xb6, 0xa3, 0x2a, 0x91, 0x40, 0xce,
0xab, 0xf9, 0x83, 0x0a, 0x5e, 0x19, 0xd0, 0x57, 0xeb, 0x55, 0x17, 0x6f, 0xf6, 0xc9, 0xbb, 0xca,
0x1d, 0x51, 0x3e, 0x22, 0x7e, 0xdc, 0xa9, 0x05, 0x76, 0x5f, 0x39, 0x32, 0xb0, 0x3e, 0xfd, 0x18,
0x6a, 0x53, 0xeb, 0xb5, 0x19, 0x90, 0x3f, 0xcc, 0x89, 0x37, 0x22, 0x8c, 0x96, 0x3c, 0xae, 0x4e,
0xad, 0xd7, 0xfd, 0xd8, 0x84, 0xea, 0x00, 0x8e, 0x17, 0xfa, 0xd4, 0x9e, 0x8f, 0x88, 0x2f, 0x97,
0x18, 0x6f, 0x19, 0x0b, 0xfa, 0x39, 0x94, 0x19, 0xa9, 0xa6, 0x63, 0xcb, 0x65, 0x55, 0x38, 0x10,
0x8f, 0x95, 0x38, 0xf1, 0x12, 0xa3, 0x94, 0xe5, 0x9d, 0x2c, 0x71, 0x89, 0x61, 0xdb, 0x36, 0xfa,
0x15, 0x28, 0xc1, 0x85, 0x13, 0x15, 0x84, 0x47, 0x0a, 0x1d, 0xea, 0x99, 0x3e, 0x99, 0xd2, 0x4b,
0xcb, 0x0d, 0xe4, 0x0a, 0xbb, 0x46, 0x8e, 0x10, 0xed, 0x0c, 0x00, 0xc7, 0x7e, 0xad, 0x0b, 0x05,
0x16, 0x11, 0xed, 0x42, 0x91, 0x37, 0x65, 0xac, 0xd2, 0x78, 0x87, 0x8e, 0xa0, 0x30, 0x76, 0x5c,
0x12, 0xc8, 0x39, 0x56, 0x43, 0x94, 0xe9, 0x68, 0xc7, 0x25, 0x6d, 0x6f, 0x4c, 0xe3, 0x2a, 0x72,
0x98, 0x76, 0x06, 0x55, 0x16, 0xf0, 0x6c, 0x66, 0x5b, 0x21, 0xf9, 0xbf, 0x85, 0xfd, 0x5b, 0x1e,
0xca, 0x89, 0x27, 0x2d, 0xba, 0x90, 0x29, 0xfa, 0x61, 0xac, 0x7b, 0xae, 0xe2, 0xdd, 0xdb, 0xf1,
0x32, 0xc2, 0x47, 0x20, 0x06, 0xce, 0x1f, 0x09, 0xd3, 0x4d, 0x1e, 0xb3, 0x35, 0x52, 0xa1, 0x7a,
0x53, 0x2c, 0x9b, 0x38, 0x6b, 0x42, 0x1f, 0x01, 0x4c, 0xa9, 0xed, 0x8c, 0x1d, 0x62, 0x9b, 0x01,
0x6b, 0x80, 0x3c, 0xae, 0x24, 0x96, 0x3e, 0x92, 0xa3, 0x76, 0x8f, 0xa4, 0x62, 0xc7, 0x9a, 0x48,
0xb6, 0x91, 0xc7, 0xf1, 0x2e, 0x2d, 0xd7, 0xb1, 0xe3, 0xaa, 0x27, 0xdb, 0x68, 0xba, 0x79, 0x74,
0x4d, 0xa4, 0x65, 0x06, 0xd8, 0xf4, 0x68, 0x56, 0xa0, 0x8f, 0xa1, 0x94, 0x4c, 0xbf, 0xa8, 0x9e,
0x6b, 0x4a, 0x7a, 0x4e, 0x46, 0x21, 0x4d, 0xe7, 0x4a, 0x0c, 0x43, 0x0a, 0x94, 0xd3, 0x56, 0x04,
0xf6, 0xd2, 0x74, 0x1f, 0xcd, 0xdc, 0x34, 0x0f, 0x2f, 0x90, 0xab, 0xaa, 0x70, 0x50, 0xc0, 0x69,
0x6a, 0x46, 0x80, 0x7e, 0x06, 0xc5, 0x63, 0x97, 0x8e, 0x2e, 0x12, 0xdd, 0xde, 0x5b, 0xdd, 0xc6,
0xec, 0x99, 0xea, 0x14, 0x87, 0x0c, 0x18, 0x25, 0x12, 0x5c, 0x4d, 0x5d, 0xc7, 0xbb, 0x30, 0x43,
0xcb, 0x9f, 0x90, 0x50, 0xde, 0xe6, 0x63, 0x3a, 0xb6, 0x0e, 0x98, 0xf1, 0x97, 0xe2, 0x9f, 0xbf,
0xdd, 0xdf, 0xd0, 0x3c, 0xa8, 0xa4, 0x71, 0xa2, 0x06, 0xa1, 0xe3, 0x71, 0x40, 0x42, 0x56, 0xcd,
0x3c, 0x8e, 0x77, 0x69, 0x8d, 0x72, 0xec, 0x79, 0xbc, 0x46, 0x08, 0xc4, 0x73, 0x2b, 0x38, 0x67,
0x75, 0xab, 0x61, 0xb6, 0x8e, 0x54, 0xf9, 0x8a, 0x58, 0x17, 0x26, 0x73, 0xf0, 0xaa, 0x95, 0x23,
0xc3, 0x53, 0x2b, 0x38, 0x8f, 0xef, 0xfb, 0x35, 0x14, 0x39, 0x4b, 0xe8, 0x09, 0x94, 0x47, 0x74,
0xee, 0x85, 0xab, 0x09, 0xbd, 0x9d, 0x15, 0x3e, 0xf3, 0xc4, 0x99, 0xa5, 0x40, 0xed, 0x04, 0x4a,
0xb1, 0x0b, 0x3d, 0x4a, 0xa7, 0x92, 0x78, 0x7c, 0x3f, 0x11, 0x67, 0xff, 0x9c, 0xfa, 0xe1, 0xda,
0x50, 0xda, 0x81, 0xc2, 0xa5, 0xe5, 0xce, 0xf9, 0xe3, 0x45, 0xcc, 0x37, 0xda, 0x5f, 0x05, 0x28,
0xe1, 0xa8, 0x08, 0x41, 0x98, 0x19, 0xf6, 0x85, 0xb5, 0x61, 0xbf, 0x92, 0x4b, 0x6e, 0x4d, 0x2e,
0x49, 0xc7, 0xe7, 0x33, 0x1d, 0xbf, 0x62, 0x4e, 0xbc, 0x93, 0xb9, 0xc2, 0x1d, 0xcc, 0x15, 0x33,
0xcc, 0x3d, 0x82, 0xad, 0xb1, 0x4f, 0xa7, 0x6c, 0x9c, 0x53, 0xdf, 0xf2, 0xaf, 0xe2, 0xee, 0xdc,
0x8c, 0xac, 0x83, 0xc4, 0xa8, 0x99, 0x50, 0xc6, 0x24, 0x98, 0x51, 0x2f, 0x20, 0xef, 0x7c, 0x36,
0x02, 0xd1, 0xb6, 0x42, 0x8b, 0x3d, 0xba, 0x86, 0xd9, 0x1a, 0xfd, 0x04, 0xc4, 0x11, 0xb5, 0xf9,
0x93, 0xb7, 0xb2, 0x3d, 0xa4, 0xfb, 0x3e, 0xf5, 0x9b, 0xd4, 0x26, 0x98, 0x01, 0xb4, 0x19, 0x48,
0x2d, 0xfa, 0xca, 0x73, 0xa9, 0x65, 0xf7, 0x7c, 0x3a, 0x89, 0xc6, 0xed, 0x3b, 0xc7, 0x46, 0x0b,
0x4a, 0x73, 0x36, 0x58, 0x92, 0xc1, 0xf1, 0xc9, 0xba, 0xd0, 0x6f, 0x06, 0xe2, 0x53, 0x28, 0x51,
0x47, 0x7c, 0x54, 0xfb, 0x5e, 0x00, 0xe5, 0xdd, 0x68, 0xd4, 0x86, 0x2a, 0x47, 0x9a, 0x99, 0x2f,
0x89, 0x83, 0xf7, 0xb9, 0x88, 0xcd, 0x18, 0x98, 0xa7, 0xeb, 0x3b, 0xff, 0x9e, 0x32, 0x6a, 0xce,
0xbf, 0x9f, 0x9a, 0x1f, 0xc2, 0x26, 0xd3, 0x59, 0xfa, 0xa7, 0x2b, 0xaa, 0xf9, 0x83, 0x02, 0xae,
0x0d, 0xb9, 0x8a, 0x98, 0x4d, 0x2b, 0x82, 0xd8, 0x73, 0xbc, 0x89, 0xb6, 0x0f, 0x85, 0xa6, 0x4b,
0x59, 0xb1, 0x8a, 0x3e, 0xb1, 0x02, 0xea, 0x25, 0x1c, 0xf2, 0xdd, 0xe1, 0xf7, 0x39, 0xa8, 0x66,
0x3e, 0x86, 0xd0, 0x63, 0xd8, 0x6a, 0x76, 0xce, 0xfa, 0x03, 0x1d, 0x9b, 0xcd, 0xae, 0x71, 0xd2,
0x3e, 0x95, 0x36, 0x94, 0xbd, 0xc5, 0x52, 0x95, 0xa7, 0x2b, 0xd0, 0xfa, 0x77, 0xce, 0x3e, 0x14,
0xda, 0x46, 0x4b, 0xff, 0x9d, 0x24, 0x28, 0x3b, 0x8b, 0xa5, 0x2a, 0x65, 0x80, 0xfc, 0xcf, 0xe4,
0xa7, 0x50, 0x63, 0x00, 0xf3, 0xac, 0xd7, 0x6a, 0x0c, 0x74, 0x29, 0xa7, 0x28, 0x8b, 0xa5, 0xba,
0x7b, 0x13, 0x17, 0xf3, 0xfd, 0x10, 0x4a, 0x58, 0xff, 0xed, 0x99, 0xde, 0x1f, 0x48, 0x79, 0x65,
0x77, 0xb1, 0x54, 0x51, 0x06, 0x98, 0x28, 0xe6, 0x11, 0x94, 0xb1, 0xde, 0xef, 0x75, 0x8d, 0xbe,
0x2e, 0x89, 0xca, 0x87, 0x8b, 0xa5, 0x7a, 0x6f, 0x0d, 0x15, 0x77, 0xe8, 0x2f, 0x60, 0xbb, 0xd5,
0x7d, 0x61, 0x74, 0xba, 0x8d, 0x96, 0xd9, 0xc3, 0xdd, 0x53, 0xac, 0xf7, 0xfb, 0x52, 0x41, 0xd9,
0x5f, 0x2c, 0xd5, 0x07, 0x19, 0xfc, 0xad, 0x86, 0xfb, 0x08, 0xc4, 0x5e, 0xdb, 0x38, 0x95, 0x8a,
0xca, 0xbd, 0xc5, 0x52, 0xfd, 0x20, 0x03, 0x8d, 0x48, 0x8d, 0x32, 0x6e, 0x76, 0xba, 0x7d, 0x5d,
0x2a, 0xdd, 0xca, 0x98, 0x91, 0x7d, 0xf8, 0x7b, 0x40, 0xb7, 0x3f, 0x17, 0xd1, 0x27, 0x20, 0x1a,
0x5d, 0x43, 0x97, 0x36, 0x78, 0xfe, 0xb7, 0x11, 0x06, 0xf5, 0x08, 0xd2, 0x20, 0xdf, 0xf9, 0xe6,
0x4b, 0x49, 0x50, 0x7e, 0xb4, 0x58, 0xaa, 0xf7, 0x6f, 0x83, 0x3a, 0xdf, 0x7c, 0x79, 0x48, 0xa1,
0x9a, 0x0d, 0xac, 0x41, 0xf9, 0x99, 0x3e, 0x68, 0xb4, 0x1a, 0x83, 0x86, 0xb4, 0xc1, 0x9f, 0x94,
0xb8, 0x9f, 0x91, 0xd0, 0x62, 0x02, 0xdc, 0x83, 0x82, 0xa1, 0x3f, 0xd7, 0xb1, 0x24, 0x28, 0xdb,
0x8b, 0xa5, 0xba, 0x99, 0x00, 0x0c, 0x72, 0x49, 0x7c, 0x54, 0x87, 0x62, 0xa3, 0xf3, 0xa2, 0xf1,
0xb2, 0x2f, 0xe5, 0x14, 0xb4, 0x58, 0xaa, 0x5b, 0x89, 0xbb, 0xe1, 0xbe, 0xb2, 0xae, 0x82, 0xc3,
0xff, 0x08, 0x50, 0xcb, 0xfe, 0x75, 0xa2, 0x3a, 0x88, 0x27, 0xed, 0x8e, 0x9e, 0x5c, 0x97, 0xf5,
0x45, 0x6b, 0x74, 0x00, 0x95, 0x56, 0x1b, 0xeb, 0xcd, 0x41, 0x17, 0xbf, 0x4c, 0x72, 0xc9, 0x82,
0x5a, 0x8e, 0xcf, 0x9a, 0x3b, 0xfa, 0x3c, 0xad, 0xf5, 0x5f, 0x3e, 0xeb, 0xb4, 0x8d, 0xaf, 0x4d,
0x16, 0x31, 0xa7, 0x3c, 0x58, 0x2c, 0xd5, 0x0f, 0xb3, 0xe0, 0x3e, 0xff, 0xdb, 0x60, 0x81, 0xbf,
0x82, 0xed, 0x04, 0xbe, 0xba, 0x20, 0xaf, 0xa8, 0x8b, 0xa5, 0xba, 0x77, 0xc7, 0x99, 0xd5, 0x3d,
0x4f, 0xe0, 0x83, 0xe4, 0xe0, 0x99, 0xf1, 0xb5, 0xd1, 0x7d, 0x61, 0x48, 0xa2, 0x52, 0x5f, 0x2c,
0x55, 0xe5, 0x8e, 0x63, 0x67, 0xde, 0x85, 0x47, 0x5f, 0x79, 0x87, 0x7f, 0x11, 0xa0, 0x92, 0x4e,
0xa8, 0x88, 0x67, 0xa3, 0x6b, 0xea, 0x18, 0x77, 0x71, 0x92, 0x78, 0xea, 0x34, 0x28, 0x5b, 0xa2,
0x8f, 0xa1, 0x74, 0xaa, 0x1b, 0x3a, 0x6e, 0x37, 0x13, 0x3d, 0xa4, 0x90, 0x53, 0xe2, 0x11, 0xdf,
0x19, 0xa1, 0x4f, 0xa1, 0x66, 0x74, 0xcd, 0xfe, 0x59, 0xf3, 0x69, 0x92, 0x31, 0x6b, 0xe0, 0x4c,
0xa8, 0xfe, 0x7c, 0x74, 0xce, 0xb2, 0x3d, 0x8c, 0xa4, 0xf3, 0xbc, 0xd1, 0x69, 0xb7, 0x38, 0x34,
0xaf, 0xc8, 0x8b, 0xa5, 0xba, 0x93, 0x42, 0xdb, 0xfc, 0xd3, 0x21, 0xc2, 0x1e, 0xda, 0x50, 0xff,
0xdf, 0xb3, 0x08, 0xa9, 0x50, 0x6c, 0xf4, 0x7a, 0xba, 0xd1, 0x4a, 0x5e, 0xbf, 0xf2, 0x35, 0x66,
0x33, 0xe2, 0xd9, 0x11, 0xe2, 0xa4, 0x8b, 0x4f, 0xf5, 0x41, 0xf2, 0xf8, 0x15, 0xe2, 0x84, 0x46,
0x7f, 0xda, 0xc7, 0x7b, 0x6f, 0x7e, 0xa8, 0x6f, 0x7c, 0xf7, 0x43, 0x7d, 0xe3, 0xcd, 0x75, 0x5d,
0xf8, 0xee, 0xba, 0x2e, 0xfc, 0xe3, 0xba, 0xbe, 0xf1, 0xaf, 0xeb, 0xba, 0xf0, 0xed, 0x3f, 0xeb,
0xc2, 0xb0, 0xc8, 0x66, 0xd7, 0x93, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xee, 0xe2, 0x0f, 0x00,
0x38, 0x0e, 0x00, 0x00,
// 1670 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x57, 0x4f, 0x73, 0xdb, 0x4c,
0x19, 0x8f, 0x6d, 0xf9, 0xdf, 0xda, 0xc9, 0xeb, 0x6c, 0xd3, 0xbc, 0x46, 0xcd, 0x9b, 0x04, 0xbd,
0x6f, 0x21, 0x78, 0x68, 0x0a, 0x2d, 0xd0, 0x19, 0x06, 0x98, 0x71, 0x6c, 0x25, 0xd1, 0xd4, 0x91,
0x8d, 0x6c, 0xa7, 0x94, 0x03, 0x1a, 0xd9, 0x5a, 0x3b, 0x9a, 0xc8, 0x5a, 0x23, 0xc9, 0x6d, 0xc3,
0x47, 0xe0, 0x13, 0x70, 0x61, 0xa6, 0x33, 0x9c, 0xb8, 0xf3, 0x21, 0xca, 0xad, 0xd3, 0x23, 0x87,
0x0e, 0x94, 0x0b, 0x47, 0x2e, 0xdc, 0x79, 0x76, 0x57, 0x92, 0xe5, 0xfc, 0x61, 0x7a, 0xe0, 0x90,
0xb1, 0xf6, 0x79, 0x7e, 0xfb, 0x3c, 0xfb, 0xfc, 0xf9, 0x3d, 0xbb, 0x41, 0xe5, 0x11, 0x99, 0x1f,
0xce, 0x7d, 0x1a, 0x52, 0x5c, 0xe2, 0x3f, 0x63, 0xea, 0xca, 0x8f, 0xa6, 0x4e, 0x78, 0xb1, 0x18,
0x1d, 0x8e, 0xe9, 0xec, 0xf1, 0x94, 0x4e, 0xe9, 0x63, 0xae, 0x19, 0x2d, 0x26, 0x7c, 0xc5, 0x17,
0xfc, 0x4b, 0x6c, 0x54, 0xe6, 0x28, 0x7f, 0x4a, 0x5c, 0x97, 0xe2, 0x3d, 0x54, 0xb1, 0xc9, 0x2b,
0x67, 0x4c, 0x4c, 0xcf, 0x9a, 0x91, 0x7a, 0x66, 0x3f, 0x73, 0x50, 0x36, 0x90, 0x10, 0xe9, 0x20,
0x61, 0x80, 0xb1, 0xeb, 0x10, 0x2f, 0x14, 0x80, 0xac, 0x00, 0x08, 0x11, 0x07, 0x3c, 0x44, 0x1b,
0x11, 0xe0, 0x15, 0xf1, 0x03, 0x87, 0x7a, 0xf5, 0x1c, 0xc7, 0xac, 0x0b, 0xe9, 0xb9, 0x10, 0x2a,
0x01, 0x2a, 0x9c, 0x12, 0xcb, 0x26, 0x3e, 0xfe, 0x1e, 0x92, 0xc2, 0xab, 0xb9, 0xf0, 0xb5, 0xf1,
0xe4, 0xfe, 0x61, 0x1c, 0xc3, 0xe1, 0x19, 0x09, 0x02, 0x6b, 0x4a, 0x06, 0xa0, 0x34, 0x38, 0x04,
0xff, 0x02, 0x9c, 0xd3, 0xd9, 0xdc, 0x07, 0x05, 0x33, 0x9c, 0xe5, 0x3b, 0x76, 0x6e, 0xec, 0x68,
0x2d, 0x31, 0x46, 0x7a, 0x83, 0xd2, 0x44, 0xeb, 0x2d, 0x77, 0x11, 0x84, 0xc4, 0x6f, 0x51, 0x6f,
0xe2, 0x4c, 0xf1, 0x0f, 0x50, 0x71, 0x42, 0x5d, 0x38, 0x45, 0x00, 0xee, 0x73, 0x07, 0x95, 0x27,
0xb5, 0xa5, 0xb1, 0x63, 0xae, 0x38, 0x92, 0xde, 0x7d, 0xdc, 0x5b, 0x33, 0x62, 0x98, 0xf2, 0xa7,
0x2c, 0x2a, 0x08, 0x0d, 0xde, 0x46, 0x59, 0xc7, 0x16, 0x29, 0x3a, 0x2a, 0x7c, 0xfa, 0xb8, 0x97,
0xd5, 0xda, 0x06, 0x48, 0xf0, 0x16, 0xca, 0xbb, 0xd6, 0x88, 0xb8, 0x51, 0x72, 0xc4, 0x02, 0x3f,
0x40, 0x65, 0x1f, 0x02, 0x36, 0xa9, 0xe7, 0x5e, 0xf1, 0x94, 0x94, 0x8c, 0x12, 0x13, 0x74, 0x61,
0x8d, 0x1f, 0x21, 0xec, 0x4c, 0x3d, 0xea, 0x13, 0x73, 0x4e, 0xfc, 0x99, 0xc3, 0x4f, 0x1b, 0xd4,
0x25, 0x8e, 0xda, 0x14, 0x9a, 0xde, 0x52, 0x81, 0xbf, 0x46, 0xeb, 0x11, 0xdc, 0x26, 0x2e, 0x09,
0x49, 0x3d, 0xcf, 0x91, 0x55, 0x21, 0x6c, 0x73, 0x19, 0xc4, 0xb6, 0x65, 0x3b, 0x81, 0x35, 0x72,
0x89, 0x19, 0x92, 0xd9, 0xdc, 0x74, 0x3c, 0x9b, 0xbc, 0x21, 0x41, 0xbd, 0xc0, 0xb1, 0x38, 0xd2,
0x0d, 0x40, 0xa5, 0x09, 0x0d, 0x04, 0x54, 0x98, 0x5b, 0x8b, 0x80, 0xd8, 0xf5, 0x22, 0xc7, 0x44,
0x2b, 0x96, 0x25, 0xd1, 0x01, 0x41, 0xbd, 0x76, 0x3d, 0x4b, 0x6d, 0xae, 0x88, 0xb3, 0x14, 0xc1,
0x94, 0x7f, 0x43, 0x96, 0x84, 0x06, 0x7f, 0x27, 0xc9, 0x52, 0xf5, 0x68, 0x9b, 0xa1, 0xfe, 0xf6,
0x71, 0xaf, 0x24, 0x74, 0x5a, 0x3b, 0x95, 0x35, 0x8c, 0xa4, 0x54, 0x47, 0xf1, 0x6f, 0xbc, 0x83,
0xca, 0x96, 0x6d, 0xb3, 0xea, 0x81, 0xeb, 0x1c, 0xb8, 0x2e, 0x1b, 0x4b, 0x01, 0x7e, 0xb6, 0xda,
0x0d, 0xd2, 0xf5, 0xfe, 0xb9, 0xab, 0x0d, 0x58, 0x29, 0xc6, 0xc4, 0x8f, 0x3a, 0x38, 0xcf, 0xfd,
0x95, 0x98, 0x80, 0xf7, 0xef, 0xb7, 0x51, 0x75, 0x66, 0xbd, 0x31, 0x03, 0xf2, 0xdb, 0x05, 0xf1,
0xc6, 0x84, 0xa7, 0x2b, 0x67, 0x54, 0x40, 0xd6, 0x8f, 0x44, 0x78, 0x17, 0x21, 0xc7, 0x0b, 0x7d,
0x6a, 0x2f, 0x60, 0x57, 0x94, 0xab, 0x94, 0x04, 0xff, 0x18, 0x95, 0x78, 0xb2, 0x4d, 0x08, 0xbc,
0x04, 0x5a, 0xe9, 0x48, 0x8e, 0x02, 0x2f, 0xf2, 0x54, 0xf3, 0xb8, 0xe3, 0x4f, 0xa3, 0xc8, 0xb1,
0x9a, 0x8d, 0x7f, 0x86, 0xe4, 0xe0, 0xd2, 0x61, 0x85, 0x12, 0x96, 0x42, 0x38, 0xab, 0xe9, 0x93,
0x19, 0x7d, 0x65, 0xb9, 0x41, 0xbd, 0xcc, 0xdd, 0xd4, 0x19, 0x42, 0x4b, 0x01, 0x8c, 0x48, 0xaf,
0x74, 0x51, 0x9e, 0x5b, 0x64, 0x55, 0x14, 0xcd, 0x1a, 0xb1, 0x37, 0x5a, 0xe1, 0x43, 0x94, 0x9f,
0x38, 0x2e, 0x24, 0x32, 0xcb, 0x6b, 0x88, 0x53, 0x9d, 0x0e, 0x62, 0xcd, 0x9b, 0xd0, 0xa8, 0x8a,
0x02, 0xa6, 0x0c, 0x51, 0x85, 0x1b, 0x1c, 0xce, 0x6d, 0x0b, 0xda, 0xe9, 0xff, 0x65, 0xf6, 0xaf,
0x39, 0x54, 0x8a, 0x35, 0x49, 0xd1, 0x33, 0xa9, 0xa2, 0x37, 0xa2, 0x79, 0x20, 0xd8, 0xbd, 0x7d,
0xd3, 0x5e, 0x6a, 0x20, 0xc0, 0xfe, 0xc0, 0xf9, 0x1d, 0xe1, 0x7c, 0xca, 0x19, 0xfc, 0x1b, 0xef,
0xa3, 0xca, 0x75, 0x12, 0xad, 0x1b, 0x69, 0x11, 0xfe, 0x0a, 0xa1, 0x19, 0xb5, 0x9d, 0x89, 0x43,
0x6c, 0x33, 0xe0, 0x0d, 0x90, 0x33, 0xca, 0xb1, 0xa4, 0x8f, 0xeb, 0xac, 0xdd, 0x19, 0x85, 0xec,
0x88, 0x2b, 0xf1, 0x92, 0x69, 0x1c, 0x0f, 0xb2, 0xed, 0xc4, 0x0c, 0x89, 0x97, 0x6c, 0xea, 0x79,
0x74, 0x85, 0xbc, 0x25, 0x0e, 0x58, 0xf7, 0x68, 0x9a, 0xb8, 0xc0, 0xa4, 0x78, 0x2a, 0xb2, 0x7a,
0xae, 0x30, 0xe9, 0x9c, 0x8c, 0x43, 0x9a, 0xcc, 0x9b, 0x08, 0x86, 0x65, 0x54, 0x4a, 0x5a, 0x11,
0xf1, 0x93, 0x26, 0x6b, 0x36, 0x8b, 0x93, 0x38, 0xc0, 0x63, 0x05, 0xd4, 0x79, 0x23, 0x09, 0x4d,
0x0f, 0xf0, 0x0f, 0x51, 0xe1, 0xc8, 0xa5, 0xe3, 0xcb, 0x98, 0xb7, 0xf7, 0x96, 0xde, 0xb8, 0x3c,
0x55, 0x9d, 0xc2, 0x88, 0x03, 0x59, 0x20, 0xc1, 0xd5, 0xcc, 0x75, 0xbc, 0x4b, 0x33, 0xb4, 0xfc,
0x29, 0x09, 0xeb, 0x9b, 0x62, 0x7c, 0x47, 0xd2, 0x01, 0x17, 0xfe, 0x54, 0xfa, 0xc3, 0xdb, 0xbd,
0x35, 0xc5, 0x43, 0xe5, 0xc4, 0x0e, 0x6b, 0x10, 0x3a, 0x99, 0x04, 0xb0, 0x23, 0xc3, 0xcf, 0x19,
0xad, 0x92, 0x1a, 0x65, 0xf9, 0xf1, 0x44, 0x8d, 0x40, 0x76, 0x61, 0x05, 0x17, 0xbc, 0x6e, 0x55,
0x83, 0x7f, 0x33, 0x56, 0xbe, 0x26, 0xd6, 0xa5, 0xc9, 0x15, 0xa2, 0x6a, 0x25, 0x26, 0x38, 0x85,
0x75, 0xe4, 0xef, 0xe7, 0xa8, 0x20, 0xb2, 0x84, 0x9f, 0xa2, 0xd2, 0x98, 0x2e, 0xbc, 0x70, 0x39,
0xb9, 0x37, 0xd3, 0xc4, 0xe7, 0x9a, 0x28, 0xb2, 0x04, 0xa8, 0x1c, 0xa3, 0x62, 0xa4, 0x82, 0x30,
0xe3, 0xa9, 0x24, 0x1d, 0xdd, 0x8f, 0xc9, 0xd9, 0xbf, 0xa0, 0x7e, 0xb8, 0x32, 0x94, 0x60, 0x94,
0x43, 0x7d, 0x17, 0xe2, 0xf0, 0x92, 0x21, 0x16, 0xca, 0x5f, 0x32, 0xa8, 0x68, 0xb0, 0x22, 0x04,
0x61, 0xea, 0x12, 0xc8, 0xaf, 0x5c, 0x02, 0x4b, 0xba, 0x64, 0x57, 0xe8, 0x12, 0x77, 0x7c, 0x2e,
0xd5, 0xf1, 0xcb, 0xcc, 0x49, 0xb7, 0x66, 0x2e, 0x7f, 0x4b, 0xe6, 0x0a, 0xa9, 0xcc, 0x41, 0xcd,
0x26, 0x3e, 0x9d, 0xf1, 0x31, 0x4f, 0x7d, 0xcb, 0xbf, 0x8a, 0xba, 0x73, 0x9d, 0x49, 0x07, 0xb1,
0x50, 0x31, 0x51, 0xc9, 0x20, 0xc1, 0x1c, 0xfa, 0x90, 0xdc, 0x79, 0x6c, 0x30, 0x0f, 0x6c, 0xb7,
0xf8, 0xa1, 0xc1, 0x3c, 0xfb, 0xc6, 0xdf, 0x45, 0xd2, 0x98, 0xda, 0xe2, 0xc8, 0x1b, 0xe9, 0x1e,
0x52, 0x7d, 0x9f, 0xc2, 0x4d, 0x6a, 0x03, 0x1b, 0x19, 0x00, 0x5e, 0x11, 0xb5, 0x36, 0x7d, 0xed,
0xb9, 0xd4, 0xb2, 0x7b, 0x3e, 0x9d, 0xb2, 0x71, 0x7b, 0xe7, 0xd8, 0x68, 0xa3, 0xe2, 0x82, 0x0f,
0x96, 0x78, 0x70, 0x7c, 0xb3, 0x4a, 0xf4, 0xeb, 0x86, 0xc4, 0x14, 0x8a, 0xd9, 0x11, 0x6d, 0x55,
0x3e, 0x64, 0x90, 0x7c, 0x37, 0x1a, 0x6b, 0xa8, 0x22, 0x90, 0x66, 0xea, 0x85, 0x71, 0xf0, 0x39,
0x8e, 0xf8, 0x8c, 0x41, 0x8b, 0xe4, 0xfb, 0xd6, 0xeb, 0x29, 0xc5, 0xe6, 0xdc, 0xe7, 0xb1, 0x19,
0x2e, 0x6e, 0xce, 0xb3, 0xe4, 0x32, 0x96, 0x20, 0xf6, 0xbc, 0x51, 0x1d, 0x09, 0x16, 0x71, 0x99,
0x52, 0x40, 0x52, 0xcf, 0xf1, 0xa6, 0xca, 0x1e, 0xca, 0xb7, 0x5c, 0xca, 0x8b, 0x55, 0x80, 0x97,
0x42, 0x00, 0x6e, 0xa2, 0x1c, 0x8a, 0x55, 0xe3, 0x43, 0x16, 0x55, 0x52, 0x8f, 0x24, 0x38, 0xcf,
0x46, 0xab, 0x33, 0xec, 0x0f, 0x54, 0xc3, 0x6c, 0x75, 0xf5, 0x63, 0xed, 0xa4, 0xb6, 0x26, 0xef,
0xfc, 0xfe, 0x8f, 0xfb, 0xf5, 0xd9, 0x12, 0xb4, 0xfa, 0xfe, 0x01, 0x17, 0x9a, 0xde, 0x56, 0x7f,
0x55, 0xcb, 0xc8, 0x5b, 0x00, 0xac, 0xa5, 0x80, 0xe2, 0x32, 0xf9, 0x3e, 0xaa, 0x72, 0x80, 0x39,
0xec, 0xb5, 0x9b, 0x03, 0xb5, 0x96, 0x95, 0x65, 0xc0, 0x6d, 0x5f, 0xc7, 0x45, 0xf9, 0xfe, 0x1a,
0x78, 0xa1, 0xfe, 0x72, 0xa8, 0xf6, 0x07, 0xb5, 0x9c, 0xbc, 0x0d, 0x40, 0x9c, 0x02, 0xc6, 0x8c,
0x79, 0x08, 0x6d, 0xa8, 0xf6, 0x7b, 0x5d, 0xbd, 0xaf, 0xd6, 0x24, 0xf9, 0x4b, 0x40, 0xdd, 0x5b,
0x41, 0x45, 0x1d, 0xfa, 0x13, 0xb4, 0xd9, 0xee, 0xbe, 0xd0, 0x3b, 0xdd, 0x66, 0xdb, 0xec, 0x19,
0xdd, 0x13, 0xd8, 0xd3, 0xaf, 0xe5, 0xe5, 0x3d, 0xc0, 0x3f, 0x48, 0xe1, 0x6f, 0x34, 0xdc, 0x57,
0x90, 0x3d, 0x4d, 0x3f, 0xa9, 0x15, 0xe4, 0x7b, 0x00, 0xfd, 0x22, 0x05, 0x65, 0x49, 0x65, 0x11,
0xb7, 0x3a, 0x5d, 0x70, 0x5d, 0xbc, 0x11, 0x31, 0x4f, 0x76, 0xe3, 0x37, 0x08, 0xdf, 0x7c, 0x46,
0xe2, 0x6f, 0x90, 0xa4, 0x77, 0x75, 0x15, 0x12, 0xca, 0xe3, 0xbf, 0x89, 0xd0, 0xa9, 0x47, 0xb0,
0x82, 0x72, 0x9d, 0x5f, 0xff, 0x08, 0x92, 0xf9, 0x2d, 0x00, 0xdd, 0xbf, 0x09, 0x02, 0x65, 0x83,
0xa2, 0x4a, 0xda, 0xb0, 0x82, 0x4a, 0x67, 0xea, 0xa0, 0x09, 0xc9, 0x6d, 0x82, 0x71, 0x7e, 0xa4,
0x58, 0x7d, 0x46, 0x42, 0x8b, 0x13, 0x70, 0x07, 0xe5, 0x75, 0xf5, 0x5c, 0x35, 0xc0, 0xf0, 0x26,
0x00, 0xd6, 0x63, 0x80, 0x4e, 0xa0, 0xaf, 0xe0, 0x35, 0x52, 0x68, 0x76, 0x5e, 0x34, 0x5f, 0xf6,
0xa1, 0x38, 0x18, 0xd4, 0x1b, 0xb1, 0xba, 0xe9, 0xbe, 0xb6, 0xae, 0x82, 0xc6, 0x7f, 0x32, 0xa8,
0x9a, 0xbe, 0x3a, 0x61, 0x83, 0x74, 0xac, 0x75, 0xd4, 0xd8, 0x5d, 0x5a, 0xc7, 0xbe, 0xf1, 0x01,
0x2a, 0xb7, 0x35, 0x43, 0x6d, 0x0d, 0xba, 0xc6, 0xcb, 0x38, 0x96, 0x34, 0xa8, 0xed, 0xf8, 0xbc,
0xb9, 0xd9, 0xb3, 0xb5, 0xda, 0x7f, 0x79, 0xd6, 0xd1, 0xf4, 0xe7, 0x26, 0xb7, 0x98, 0x95, 0x1f,
0x00, 0xf8, 0xcb, 0x34, 0xb8, 0x2f, 0xae, 0x0d, 0x6e, 0xf8, 0x19, 0xda, 0x8c, 0xe1, 0x4b, 0x07,
0x39, 0x79, 0x1f, 0xf6, 0xec, 0xdc, 0xb2, 0x67, 0xe9, 0xe7, 0x29, 0xfa, 0x22, 0xde, 0x38, 0xd4,
0x9f, 0xeb, 0xd0, 0x16, 0xd0, 0x39, 0xbb, 0xb0, 0x4d, 0xbe, 0x65, 0xdb, 0xd0, 0xbb, 0xf4, 0xa0,
0x29, 0x1a, 0x7f, 0xce, 0xa0, 0x72, 0x32, 0xa1, 0x58, 0x9e, 0xf5, 0xae, 0xa9, 0x1a, 0x46, 0xd7,
0x88, 0x03, 0x4f, 0x94, 0x3a, 0xe5, 0x9f, 0xf0, 0xf4, 0x2b, 0x9e, 0xa8, 0xba, 0x6a, 0x68, 0xad,
0x98, 0x0f, 0x09, 0xe4, 0x84, 0x78, 0xc4, 0x77, 0xc6, 0xf0, 0xcf, 0x4a, 0x15, 0xcc, 0xf4, 0x87,
0xad, 0xd3, 0x38, 0x62, 0xde, 0xc0, 0x29, 0x53, 0xfd, 0xc5, 0xf8, 0x82, 0x47, 0xdb, 0x60, 0xd4,
0x39, 0x6f, 0x76, 0xb4, 0xb6, 0x80, 0xe6, 0xe4, 0x3a, 0x40, 0xb7, 0x12, 0xa8, 0x26, 0x9e, 0x0e,
0x0c, 0xdb, 0xb0, 0xd1, 0xee, 0xff, 0x9e, 0x45, 0xf0, 0xaa, 0x29, 0x34, 0x7b, 0x3d, 0x55, 0x6f,
0xc7, 0xa7, 0x5f, 0xea, 0x9a, 0xf3, 0x39, 0xf1, 0x6c, 0x86, 0x38, 0xee, 0x1a, 0x27, 0xea, 0x20,
0x3e, 0xfc, 0x12, 0x71, 0x4c, 0xd9, 0xa5, 0x7d, 0xb4, 0xf3, 0xee, 0x1f, 0xbb, 0x6b, 0xef, 0xe1,
0xef, 0xdd, 0xa7, 0xdd, 0xcc, 0x7b, 0xf8, 0xfb, 0xfb, 0xa7, 0xdd, 0xb5, 0x7f, 0xc1, 0xef, 0xdb,
0x7f, 0xee, 0x66, 0x46, 0x05, 0x3e, 0xbb, 0x9e, 0xfe, 0x37, 0x00, 0x00, 0xff, 0xff, 0x93, 0x35,
0x80, 0x49, 0x50, 0x0e, 0x00, 0x00,
}

View File

@ -58,6 +58,7 @@ message Folder {
bool ignore_permissions = 4;
bool ignore_delete = 5;
bool disable_temp_indexes = 6;
bool paused = 7;
repeated Device devices = 16 [(gogoproto.nullable) = false];
}

View File

@ -427,16 +427,16 @@ var (
)
var fileDescriptorDeviceidTest = []byte{
// 176 bytes of a gzipped FileDescriptorProto
// 171 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x12, 0x4e, 0x49, 0x2d, 0xcb,
0x4c, 0x4e, 0xcd, 0x4c, 0x89, 0x2f, 0x49, 0x2d, 0x2e, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17,
0xe2, 0x00, 0x53, 0xc9, 0xf9, 0x39, 0x52, 0xba, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9,
0xf9, 0xb9, 0xfa, 0xe9, 0xf9, 0xe9, 0xf9, 0xfa, 0x60, 0x99, 0xa4, 0xd2, 0x34, 0x30, 0x0f, 0xcc,
0x01, 0xb3, 0x20, 0x1a, 0x95, 0x54, 0xb9, 0xf8, 0x43, 0x52, 0x8b, 0x4b, 0xfc, 0x73, 0x52, 0x5c,
0xc0, 0xc6, 0x7a, 0xba, 0x08, 0x09, 0x71, 0xb1, 0x80, 0x4c, 0x96, 0x60, 0x54, 0x60, 0xd4, 0xe0,
0x09, 0x02, 0xb3, 0x95, 0xcc, 0x21, 0xca, 0xfc, 0x52, 0xcb, 0xe1, 0xca, 0x54, 0x90, 0x95, 0x39,
0x09, 0x9c, 0xb8, 0x27, 0xcf, 0x70, 0xeb, 0x9e, 0x3c, 0x07, 0x4c, 0x1e, 0xa2, 0xd1, 0x49, 0xe6,
0xc4, 0x43, 0x39, 0x86, 0x0b, 0x0f, 0xe5, 0x18, 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e,
0xf1, 0xc1, 0x23, 0x39, 0x86, 0x17, 0x8f, 0xe4, 0x18, 0x16, 0x3c, 0x96, 0x63, 0x4c, 0x62, 0x03,
0x3b, 0xc2, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x35, 0x9c, 0x00, 0x78, 0xd4, 0x00, 0x00, 0x00,
0x01, 0xb3, 0x20, 0x1a, 0x95, 0x54, 0xb9, 0xf8, 0x43, 0x80, 0xc6, 0xf8, 0xe7, 0xa4, 0xb8, 0x80,
0x8d, 0xf5, 0x74, 0x11, 0x12, 0xe2, 0x62, 0x01, 0x99, 0x2c, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x13,
0x04, 0x66, 0x2b, 0x99, 0x43, 0x94, 0xf9, 0xa5, 0x96, 0xc3, 0x95, 0xa9, 0x20, 0x2b, 0x73, 0x12,
0x38, 0x71, 0x4f, 0x9e, 0xe1, 0xd6, 0x3d, 0x79, 0x0e, 0x98, 0x3c, 0x44, 0xa3, 0x93, 0xcc, 0x89,
0x87, 0x72, 0x0c, 0x17, 0x80, 0xf8, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x40, 0xfc, 0xe0, 0x91, 0x1c,
0xc3, 0x0b, 0x20, 0x5e, 0xf0, 0x58, 0x8e, 0x31, 0x89, 0x0d, 0xec, 0x08, 0x63, 0x40, 0x00, 0x00,
0x00, 0xff, 0xff, 0x35, 0x9c, 0x00, 0x78, 0xd4, 0x00, 0x00, 0x00,
}