mirror of
https://github.com/octoleo/syncthing.git
synced 2025-01-03 15:17:25 +00:00
Refactor config types into separate files
This commit is contained in:
parent
e3c0fba34b
commit
83154569b1
@ -12,7 +12,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -21,7 +20,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/lib/osutil"
|
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
@ -94,270 +92,6 @@ func (cfg Configuration) Copy() Configuration {
|
|||||||
return newCfg
|
return newCfg
|
||||||
}
|
}
|
||||||
|
|
||||||
type FolderConfiguration struct {
|
|
||||||
ID string `xml:"id,attr" json:"id"`
|
|
||||||
RawPath string `xml:"path,attr" json:"path"`
|
|
||||||
Devices []FolderDeviceConfiguration `xml:"device" json:"devices"`
|
|
||||||
ReadOnly bool `xml:"ro,attr" json:"readOnly"`
|
|
||||||
RescanIntervalS int `xml:"rescanIntervalS,attr" json:"rescanIntervalS"`
|
|
||||||
IgnorePerms bool `xml:"ignorePerms,attr" json:"ignorePerms"`
|
|
||||||
AutoNormalize bool `xml:"autoNormalize,attr" json:"autoNormalize"`
|
|
||||||
MinDiskFreePct float64 `xml:"minDiskFreePct" json:"minDiskFreePct"`
|
|
||||||
Versioning VersioningConfiguration `xml:"versioning" json:"versioning"`
|
|
||||||
Copiers int `xml:"copiers" json:"copiers"` // This defines how many files are handled concurrently.
|
|
||||||
Pullers int `xml:"pullers" json:"pullers"` // Defines how many blocks are fetched at the same time, possibly between separate copier routines.
|
|
||||||
Hashers int `xml:"hashers" json:"hashers"` // Less than one sets the value to the number of cores. These are CPU bound due to hashing.
|
|
||||||
Order PullOrder `xml:"order" json:"order"`
|
|
||||||
IgnoreDelete bool `xml:"ignoreDelete" json:"ignoreDelete"`
|
|
||||||
ScanProgressIntervalS int `xml:"scanProgressIntervalS" json:"scanProgressIntervalS"` // Set to a negative value to disable. Value of 0 will get replaced with value of 2 (default value)
|
|
||||||
PullerSleepS int `xml:"pullerSleepS" json:"pullerSleepS"`
|
|
||||||
PullerPauseS int `xml:"pullerPauseS" json:"pullerPauseS"`
|
|
||||||
MaxConflicts int `xml:"maxConflicts" json:"maxConflicts"`
|
|
||||||
|
|
||||||
Invalid string `xml:"-" json:"invalid"` // Set at runtime when there is an error, not saved
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f FolderConfiguration) Copy() FolderConfiguration {
|
|
||||||
c := f
|
|
||||||
c.Devices = make([]FolderDeviceConfiguration, len(f.Devices))
|
|
||||||
copy(c.Devices, f.Devices)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f FolderConfiguration) Path() string {
|
|
||||||
// This is intentionally not a pointer method, because things like
|
|
||||||
// cfg.Folders["default"].Path() should be valid.
|
|
||||||
|
|
||||||
// Attempt tilde expansion; leave unchanged in case of error
|
|
||||||
if path, err := osutil.ExpandTilde(f.RawPath); err == nil {
|
|
||||||
f.RawPath = path
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt absolutification; leave unchanged in case of error
|
|
||||||
if !filepath.IsAbs(f.RawPath) {
|
|
||||||
// Abs() looks like a fairly expensive syscall on Windows, while
|
|
||||||
// IsAbs() is a whole bunch of string mangling. I think IsAbs() may be
|
|
||||||
// somewhat faster in the general case, hence the outer if...
|
|
||||||
if path, err := filepath.Abs(f.RawPath); err == nil {
|
|
||||||
f.RawPath = path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to enable long filename support on Windows. We may still not
|
|
||||||
// have an absolute path here if the previous steps failed.
|
|
||||||
if runtime.GOOS == "windows" && filepath.IsAbs(f.RawPath) && !strings.HasPrefix(f.RawPath, `\\`) {
|
|
||||||
return `\\?\` + f.RawPath
|
|
||||||
}
|
|
||||||
|
|
||||||
return f.RawPath
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FolderConfiguration) CreateMarker() error {
|
|
||||||
if !f.HasMarker() {
|
|
||||||
marker := filepath.Join(f.Path(), ".stfolder")
|
|
||||||
fd, err := os.Create(marker)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fd.Close()
|
|
||||||
osutil.HideFile(marker)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FolderConfiguration) HasMarker() bool {
|
|
||||||
_, err := os.Stat(filepath.Join(f.Path(), ".stfolder"))
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FolderConfiguration) DeviceIDs() []protocol.DeviceID {
|
|
||||||
deviceIDs := make([]protocol.DeviceID, len(f.Devices))
|
|
||||||
for i, n := range f.Devices {
|
|
||||||
deviceIDs[i] = n.DeviceID
|
|
||||||
}
|
|
||||||
return deviceIDs
|
|
||||||
}
|
|
||||||
|
|
||||||
type VersioningConfiguration struct {
|
|
||||||
Type string `xml:"type,attr" json:"type"`
|
|
||||||
Params map[string]string `json:"params"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type InternalVersioningConfiguration struct {
|
|
||||||
Type string `xml:"type,attr,omitempty"`
|
|
||||||
Params []InternalParam `xml:"param"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type InternalParam struct {
|
|
||||||
Key string `xml:"key,attr"`
|
|
||||||
Val string `xml:"val,attr"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *VersioningConfiguration) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
|
||||||
var tmp InternalVersioningConfiguration
|
|
||||||
tmp.Type = c.Type
|
|
||||||
for k, v := range c.Params {
|
|
||||||
tmp.Params = append(tmp.Params, InternalParam{k, v})
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.EncodeElement(tmp, start)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *VersioningConfiguration) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|
||||||
var tmp InternalVersioningConfiguration
|
|
||||||
err := d.DecodeElement(&tmp, &start)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Type = tmp.Type
|
|
||||||
c.Params = make(map[string]string, len(tmp.Params))
|
|
||||||
for _, p := range tmp.Params {
|
|
||||||
c.Params[p.Key] = p.Val
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeviceConfiguration struct {
|
|
||||||
DeviceID protocol.DeviceID `xml:"id,attr" json:"deviceID"`
|
|
||||||
Name string `xml:"name,attr,omitempty" json:"name"`
|
|
||||||
Addresses []string `xml:"address,omitempty" json:"addresses"`
|
|
||||||
Compression protocol.Compression `xml:"compression,attr" json:"compression"`
|
|
||||||
CertName string `xml:"certName,attr,omitempty" json:"certName"`
|
|
||||||
Introducer bool `xml:"introducer,attr" json:"introducer"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (orig DeviceConfiguration) Copy() DeviceConfiguration {
|
|
||||||
c := orig
|
|
||||||
c.Addresses = make([]string, len(orig.Addresses))
|
|
||||||
copy(c.Addresses, orig.Addresses)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
type FolderDeviceConfiguration struct {
|
|
||||||
DeviceID protocol.DeviceID `xml:"id,attr" json:"deviceID"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type OptionsConfiguration struct {
|
|
||||||
ListenAddress []string `xml:"listenAddress" json:"listenAddress" default:"tcp://0.0.0.0:22000"`
|
|
||||||
GlobalAnnServers []string `xml:"globalAnnounceServer" json:"globalAnnounceServers" json:"globalAnnounceServer" default:"default"`
|
|
||||||
GlobalAnnEnabled bool `xml:"globalAnnounceEnabled" json:"globalAnnounceEnabled" default:"true"`
|
|
||||||
LocalAnnEnabled bool `xml:"localAnnounceEnabled" json:"localAnnounceEnabled" default:"true"`
|
|
||||||
LocalAnnPort int `xml:"localAnnouncePort" json:"localAnnouncePort" default:"21027"`
|
|
||||||
LocalAnnMCAddr string `xml:"localAnnounceMCAddr" json:"localAnnounceMCAddr" default:"[ff12::8384]:21027"`
|
|
||||||
RelayServers []string `xml:"relayServer" json:"relayServers" default:"dynamic+https://relays.syncthing.net/endpoint"`
|
|
||||||
MaxSendKbps int `xml:"maxSendKbps" json:"maxSendKbps"`
|
|
||||||
MaxRecvKbps int `xml:"maxRecvKbps" json:"maxRecvKbps"`
|
|
||||||
ReconnectIntervalS int `xml:"reconnectionIntervalS" json:"reconnectionIntervalS" default:"60"`
|
|
||||||
RelaysEnabled bool `xml:"relaysEnabled" json:"relaysEnabled" default:"true"`
|
|
||||||
RelayReconnectIntervalM int `xml:"relayReconnectIntervalM" json:"relayReconnectIntervalM" default:"10"`
|
|
||||||
RelayWithoutGlobalAnn bool `xml:"relayWithoutGlobalAnn" json:"relayWithoutGlobalAnn" default:"false"`
|
|
||||||
StartBrowser bool `xml:"startBrowser" json:"startBrowser" default:"true"`
|
|
||||||
UPnPEnabled bool `xml:"upnpEnabled" json:"upnpEnabled" default:"true"`
|
|
||||||
UPnPLeaseM int `xml:"upnpLeaseMinutes" json:"upnpLeaseMinutes" default:"60"`
|
|
||||||
UPnPRenewalM int `xml:"upnpRenewalMinutes" json:"upnpRenewalMinutes" default:"30"`
|
|
||||||
UPnPTimeoutS int `xml:"upnpTimeoutSeconds" json:"upnpTimeoutSeconds" default:"10"`
|
|
||||||
URAccepted int `xml:"urAccepted" json:"urAccepted"` // Accepted usage reporting version; 0 for off (undecided), -1 for off (permanently)
|
|
||||||
URUniqueID string `xml:"urUniqueID" json:"urUniqueId"` // Unique ID for reporting purposes, regenerated when UR is turned on.
|
|
||||||
URURL string `xml:"urURL" json:"urURL" default:"https://data.syncthing.net/newdata"`
|
|
||||||
URPostInsecurely bool `xml:"urPostInsecurely" json:"urPostInsecurely" default:"false"` // For testing
|
|
||||||
URInitialDelayS int `xml:"urInitialDelayS" json:"urInitialDelayS" default:"1800"`
|
|
||||||
RestartOnWakeup bool `xml:"restartOnWakeup" json:"restartOnWakeup" default:"true"`
|
|
||||||
AutoUpgradeIntervalH int `xml:"autoUpgradeIntervalH" json:"autoUpgradeIntervalH" default:"12"` // 0 for off
|
|
||||||
KeepTemporariesH int `xml:"keepTemporariesH" json:"keepTemporariesH" default:"24"` // 0 for off
|
|
||||||
CacheIgnoredFiles bool `xml:"cacheIgnoredFiles" json:"cacheIgnoredFiles" default:"true"`
|
|
||||||
ProgressUpdateIntervalS int `xml:"progressUpdateIntervalS" json:"progressUpdateIntervalS" default:"5"`
|
|
||||||
SymlinksEnabled bool `xml:"symlinksEnabled" json:"symlinksEnabled" default:"true"`
|
|
||||||
LimitBandwidthInLan bool `xml:"limitBandwidthInLan" json:"limitBandwidthInLan" default:"false"`
|
|
||||||
DatabaseBlockCacheMiB int `xml:"databaseBlockCacheMiB" json:"databaseBlockCacheMiB" default:"0"`
|
|
||||||
MinHomeDiskFreePct float64 `xml:"minHomeDiskFreePct" json:"minHomeDiskFreePct" default:"1"`
|
|
||||||
ReleasesURL string `xml:"releasesURL" json:"releasesURL" default:"https://api.github.com/repos/syncthing/syncthing/releases?per_page=30"`
|
|
||||||
AlwaysLocalNets []string `xml:"alwaysLocalNet" json:"alwaysLocalNets"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (orig OptionsConfiguration) Copy() OptionsConfiguration {
|
|
||||||
c := orig
|
|
||||||
c.ListenAddress = make([]string, len(orig.ListenAddress))
|
|
||||||
copy(c.ListenAddress, orig.ListenAddress)
|
|
||||||
c.GlobalAnnServers = make([]string, len(orig.GlobalAnnServers))
|
|
||||||
copy(c.GlobalAnnServers, orig.GlobalAnnServers)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
type GUIConfiguration struct {
|
|
||||||
Enabled bool `xml:"enabled,attr" json:"enabled" default:"true"`
|
|
||||||
RawAddress string `xml:"address" json:"address" default:"127.0.0.1:8384"`
|
|
||||||
User string `xml:"user,omitempty" json:"user"`
|
|
||||||
Password string `xml:"password,omitempty" json:"password"`
|
|
||||||
RawUseTLS bool `xml:"tls,attr" json:"useTLS"`
|
|
||||||
RawAPIKey string `xml:"apikey,omitempty" json:"apiKey"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c GUIConfiguration) Address() string {
|
|
||||||
if override := os.Getenv("STGUIADDRESS"); override != "" {
|
|
||||||
// This value may be of the form "scheme://address:port" or just
|
|
||||||
// "address:port". We need to chop off the scheme. We try to parse it as
|
|
||||||
// an URL if it contains a slash. If that fails, return it as is and let
|
|
||||||
// some other error handling handle it.
|
|
||||||
|
|
||||||
if strings.Contains(override, "/") {
|
|
||||||
url, err := url.Parse(override)
|
|
||||||
if err != nil {
|
|
||||||
return override
|
|
||||||
}
|
|
||||||
return url.Host
|
|
||||||
}
|
|
||||||
|
|
||||||
return override
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.RawAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c GUIConfiguration) UseTLS() bool {
|
|
||||||
if override := os.Getenv("STGUIADDRESS"); override != "" {
|
|
||||||
return strings.HasPrefix(override, "https:")
|
|
||||||
}
|
|
||||||
return c.RawUseTLS
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c GUIConfiguration) URL() string {
|
|
||||||
u := url.URL{
|
|
||||||
Scheme: "http",
|
|
||||||
Host: c.Address(),
|
|
||||||
Path: "/",
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.UseTLS() {
|
|
||||||
u.Scheme = "https"
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(u.Host, ":") {
|
|
||||||
// Empty host, i.e. ":port", use IPv4 localhost
|
|
||||||
u.Host = "127.0.0.1" + u.Host
|
|
||||||
} else if strings.HasPrefix(u.Host, "0.0.0.0:") {
|
|
||||||
// IPv4 all zeroes host, convert to IPv4 localhost
|
|
||||||
u.Host = "127.0.0.1" + u.Host[7:]
|
|
||||||
} else if strings.HasPrefix(u.Host, "[::]:") {
|
|
||||||
// IPv6 all zeroes host, convert to IPv6 localhost
|
|
||||||
u.Host = "[::1]" + u.Host[4:]
|
|
||||||
}
|
|
||||||
|
|
||||||
return u.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c GUIConfiguration) APIKey() string {
|
|
||||||
if override := os.Getenv("STGUIAPIKEY"); override != "" {
|
|
||||||
return override
|
|
||||||
}
|
|
||||||
return c.RawAPIKey
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(myID protocol.DeviceID) Configuration {
|
func New(myID protocol.DeviceID) Configuration {
|
||||||
var cfg Configuration
|
var cfg Configuration
|
||||||
cfg.Version = CurrentVersion
|
cfg.Version = CurrentVersion
|
||||||
@ -811,30 +545,6 @@ loop:
|
|||||||
return devices[0:count]
|
return devices[0:count]
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeviceConfigurationList []DeviceConfiguration
|
|
||||||
|
|
||||||
func (l DeviceConfigurationList) Less(a, b int) bool {
|
|
||||||
return l[a].DeviceID.Compare(l[b].DeviceID) == -1
|
|
||||||
}
|
|
||||||
func (l DeviceConfigurationList) Swap(a, b int) {
|
|
||||||
l[a], l[b] = l[b], l[a]
|
|
||||||
}
|
|
||||||
func (l DeviceConfigurationList) Len() int {
|
|
||||||
return len(l)
|
|
||||||
}
|
|
||||||
|
|
||||||
type FolderDeviceConfigurationList []FolderDeviceConfiguration
|
|
||||||
|
|
||||||
func (l FolderDeviceConfigurationList) Less(a, b int) bool {
|
|
||||||
return l[a].DeviceID.Compare(l[b].DeviceID) == -1
|
|
||||||
}
|
|
||||||
func (l FolderDeviceConfigurationList) Swap(a, b int) {
|
|
||||||
l[a], l[b] = l[b], l[a]
|
|
||||||
}
|
|
||||||
func (l FolderDeviceConfigurationList) Len() int {
|
|
||||||
return len(l)
|
|
||||||
}
|
|
||||||
|
|
||||||
// randomCharset contains the characters that can make up a randomString().
|
// randomCharset contains the characters that can make up a randomString().
|
||||||
const randomCharset = "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-"
|
const randomCharset = "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-"
|
||||||
|
|
||||||
@ -847,57 +557,3 @@ func randomString(l int) string {
|
|||||||
}
|
}
|
||||||
return string(bs)
|
return string(bs)
|
||||||
}
|
}
|
||||||
|
|
||||||
type PullOrder int
|
|
||||||
|
|
||||||
const (
|
|
||||||
OrderRandom PullOrder = iota // default is random
|
|
||||||
OrderAlphabetic
|
|
||||||
OrderSmallestFirst
|
|
||||||
OrderLargestFirst
|
|
||||||
OrderOldestFirst
|
|
||||||
OrderNewestFirst
|
|
||||||
)
|
|
||||||
|
|
||||||
func (o PullOrder) String() string {
|
|
||||||
switch o {
|
|
||||||
case OrderRandom:
|
|
||||||
return "random"
|
|
||||||
case OrderAlphabetic:
|
|
||||||
return "alphabetic"
|
|
||||||
case OrderSmallestFirst:
|
|
||||||
return "smallestFirst"
|
|
||||||
case OrderLargestFirst:
|
|
||||||
return "largestFirst"
|
|
||||||
case OrderOldestFirst:
|
|
||||||
return "oldestFirst"
|
|
||||||
case OrderNewestFirst:
|
|
||||||
return "newestFirst"
|
|
||||||
default:
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o PullOrder) MarshalText() ([]byte, error) {
|
|
||||||
return []byte(o.String()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *PullOrder) UnmarshalText(bs []byte) error {
|
|
||||||
switch string(bs) {
|
|
||||||
case "random":
|
|
||||||
*o = OrderRandom
|
|
||||||
case "alphabetic":
|
|
||||||
*o = OrderAlphabetic
|
|
||||||
case "smallestFirst":
|
|
||||||
*o = OrderSmallestFirst
|
|
||||||
case "largestFirst":
|
|
||||||
*o = OrderLargestFirst
|
|
||||||
case "oldestFirst":
|
|
||||||
*o = OrderOldestFirst
|
|
||||||
case "newestFirst":
|
|
||||||
*o = OrderNewestFirst
|
|
||||||
default:
|
|
||||||
*o = OrderRandom
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
39
lib/config/deviceconfiguration.go
Normal file
39
lib/config/deviceconfiguration.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (C) 2014 The Syncthing Authors.
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import "github.com/syncthing/syncthing/lib/protocol"
|
||||||
|
|
||||||
|
type DeviceConfiguration struct {
|
||||||
|
DeviceID protocol.DeviceID `xml:"id,attr" json:"deviceID"`
|
||||||
|
Name string `xml:"name,attr,omitempty" json:"name"`
|
||||||
|
Addresses []string `xml:"address,omitempty" json:"addresses"`
|
||||||
|
Compression protocol.Compression `xml:"compression,attr" json:"compression"`
|
||||||
|
CertName string `xml:"certName,attr,omitempty" json:"certName"`
|
||||||
|
Introducer bool `xml:"introducer,attr" json:"introducer"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (orig DeviceConfiguration) Copy() DeviceConfiguration {
|
||||||
|
c := orig
|
||||||
|
c.Addresses = make([]string, len(orig.Addresses))
|
||||||
|
copy(c.Addresses, orig.Addresses)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeviceConfigurationList []DeviceConfiguration
|
||||||
|
|
||||||
|
func (l DeviceConfigurationList) Less(a, b int) bool {
|
||||||
|
return l[a].DeviceID.Compare(l[b].DeviceID) == -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l DeviceConfigurationList) Swap(a, b int) {
|
||||||
|
l[a], l[b] = l[b], l[a]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l DeviceConfigurationList) Len() int {
|
||||||
|
return len(l)
|
||||||
|
}
|
123
lib/config/folderconfiguration.go
Normal file
123
lib/config/folderconfiguration.go
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
// Copyright (C) 2014 The Syncthing Authors.
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/syncthing/syncthing/lib/osutil"
|
||||||
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FolderConfiguration struct {
|
||||||
|
ID string `xml:"id,attr" json:"id"`
|
||||||
|
RawPath string `xml:"path,attr" json:"path"`
|
||||||
|
Devices []FolderDeviceConfiguration `xml:"device" json:"devices"`
|
||||||
|
ReadOnly bool `xml:"ro,attr" json:"readOnly"`
|
||||||
|
RescanIntervalS int `xml:"rescanIntervalS,attr" json:"rescanIntervalS"`
|
||||||
|
IgnorePerms bool `xml:"ignorePerms,attr" json:"ignorePerms"`
|
||||||
|
AutoNormalize bool `xml:"autoNormalize,attr" json:"autoNormalize"`
|
||||||
|
MinDiskFreePct float64 `xml:"minDiskFreePct" json:"minDiskFreePct"`
|
||||||
|
Versioning VersioningConfiguration `xml:"versioning" json:"versioning"`
|
||||||
|
Copiers int `xml:"copiers" json:"copiers"` // This defines how many files are handled concurrently.
|
||||||
|
Pullers int `xml:"pullers" json:"pullers"` // Defines how many blocks are fetched at the same time, possibly between separate copier routines.
|
||||||
|
Hashers int `xml:"hashers" json:"hashers"` // Less than one sets the value to the number of cores. These are CPU bound due to hashing.
|
||||||
|
Order PullOrder `xml:"order" json:"order"`
|
||||||
|
IgnoreDelete bool `xml:"ignoreDelete" json:"ignoreDelete"`
|
||||||
|
ScanProgressIntervalS int `xml:"scanProgressIntervalS" json:"scanProgressIntervalS"` // Set to a negative value to disable. Value of 0 will get replaced with value of 2 (default value)
|
||||||
|
PullerSleepS int `xml:"pullerSleepS" json:"pullerSleepS"`
|
||||||
|
PullerPauseS int `xml:"pullerPauseS" json:"pullerPauseS"`
|
||||||
|
MaxConflicts int `xml:"maxConflicts" json:"maxConflicts"`
|
||||||
|
|
||||||
|
Invalid string `xml:"-" json:"invalid"` // Set at runtime when there is an error, not saved
|
||||||
|
}
|
||||||
|
|
||||||
|
type FolderDeviceConfiguration struct {
|
||||||
|
DeviceID protocol.DeviceID `xml:"id,attr" json:"deviceID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FolderConfiguration) Copy() FolderConfiguration {
|
||||||
|
c := f
|
||||||
|
c.Devices = make([]FolderDeviceConfiguration, len(f.Devices))
|
||||||
|
copy(c.Devices, f.Devices)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FolderConfiguration) Path() string {
|
||||||
|
// This is intentionally not a pointer method, because things like
|
||||||
|
// cfg.Folders["default"].Path() should be valid.
|
||||||
|
|
||||||
|
// Attempt tilde expansion; leave unchanged in case of error
|
||||||
|
if path, err := osutil.ExpandTilde(f.RawPath); err == nil {
|
||||||
|
f.RawPath = path
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt absolutification; leave unchanged in case of error
|
||||||
|
if !filepath.IsAbs(f.RawPath) {
|
||||||
|
// Abs() looks like a fairly expensive syscall on Windows, while
|
||||||
|
// IsAbs() is a whole bunch of string mangling. I think IsAbs() may be
|
||||||
|
// somewhat faster in the general case, hence the outer if...
|
||||||
|
if path, err := filepath.Abs(f.RawPath); err == nil {
|
||||||
|
f.RawPath = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to enable long filename support on Windows. We may still not
|
||||||
|
// have an absolute path here if the previous steps failed.
|
||||||
|
if runtime.GOOS == "windows" && filepath.IsAbs(f.RawPath) && !strings.HasPrefix(f.RawPath, `\\`) {
|
||||||
|
return `\\?\` + f.RawPath
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.RawPath
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FolderConfiguration) CreateMarker() error {
|
||||||
|
if !f.HasMarker() {
|
||||||
|
marker := filepath.Join(f.Path(), ".stfolder")
|
||||||
|
fd, err := os.Create(marker)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fd.Close()
|
||||||
|
osutil.HideFile(marker)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FolderConfiguration) HasMarker() bool {
|
||||||
|
_, err := os.Stat(filepath.Join(f.Path(), ".stfolder"))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FolderConfiguration) DeviceIDs() []protocol.DeviceID {
|
||||||
|
deviceIDs := make([]protocol.DeviceID, len(f.Devices))
|
||||||
|
for i, n := range f.Devices {
|
||||||
|
deviceIDs[i] = n.DeviceID
|
||||||
|
}
|
||||||
|
return deviceIDs
|
||||||
|
}
|
||||||
|
|
||||||
|
type FolderDeviceConfigurationList []FolderDeviceConfiguration
|
||||||
|
|
||||||
|
func (l FolderDeviceConfigurationList) Less(a, b int) bool {
|
||||||
|
return l[a].DeviceID.Compare(l[b].DeviceID) == -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l FolderDeviceConfigurationList) Swap(a, b int) {
|
||||||
|
l[a], l[b] = l[b], l[a]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l FolderDeviceConfigurationList) Len() int {
|
||||||
|
return len(l)
|
||||||
|
}
|
82
lib/config/guiconfiguration.go
Normal file
82
lib/config/guiconfiguration.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// Copyright (C) 2014 The Syncthing Authors.
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GUIConfiguration struct {
|
||||||
|
Enabled bool `xml:"enabled,attr" json:"enabled" default:"true"`
|
||||||
|
RawAddress string `xml:"address" json:"address" default:"127.0.0.1:8384"`
|
||||||
|
User string `xml:"user,omitempty" json:"user"`
|
||||||
|
Password string `xml:"password,omitempty" json:"password"`
|
||||||
|
RawUseTLS bool `xml:"tls,attr" json:"useTLS"`
|
||||||
|
RawAPIKey string `xml:"apikey,omitempty" json:"apiKey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c GUIConfiguration) Address() string {
|
||||||
|
if override := os.Getenv("STGUIADDRESS"); override != "" {
|
||||||
|
// This value may be of the form "scheme://address:port" or just
|
||||||
|
// "address:port". We need to chop off the scheme. We try to parse it as
|
||||||
|
// an URL if it contains a slash. If that fails, return it as is and let
|
||||||
|
// some other error handling handle it.
|
||||||
|
|
||||||
|
if strings.Contains(override, "/") {
|
||||||
|
url, err := url.Parse(override)
|
||||||
|
if err != nil {
|
||||||
|
return override
|
||||||
|
}
|
||||||
|
return url.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
return override
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.RawAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c GUIConfiguration) UseTLS() bool {
|
||||||
|
if override := os.Getenv("STGUIADDRESS"); override != "" {
|
||||||
|
return strings.HasPrefix(override, "https:")
|
||||||
|
}
|
||||||
|
return c.RawUseTLS
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c GUIConfiguration) URL() string {
|
||||||
|
u := url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: c.Address(),
|
||||||
|
Path: "/",
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.UseTLS() {
|
||||||
|
u.Scheme = "https"
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(u.Host, ":") {
|
||||||
|
// Empty host, i.e. ":port", use IPv4 localhost
|
||||||
|
u.Host = "127.0.0.1" + u.Host
|
||||||
|
} else if strings.HasPrefix(u.Host, "0.0.0.0:") {
|
||||||
|
// IPv4 all zeroes host, convert to IPv4 localhost
|
||||||
|
u.Host = "127.0.0.1" + u.Host[7:]
|
||||||
|
} else if strings.HasPrefix(u.Host, "[::]:") {
|
||||||
|
// IPv6 all zeroes host, convert to IPv6 localhost
|
||||||
|
u.Host = "[::1]" + u.Host[4:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c GUIConfiguration) APIKey() string {
|
||||||
|
if override := os.Getenv("STGUIAPIKEY"); override != "" {
|
||||||
|
return override
|
||||||
|
}
|
||||||
|
return c.RawAPIKey
|
||||||
|
}
|
53
lib/config/optionsconfiguration.go
Normal file
53
lib/config/optionsconfiguration.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// Copyright (C) 2014 The Syncthing Authors.
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
type OptionsConfiguration struct {
|
||||||
|
ListenAddress []string `xml:"listenAddress" json:"listenAddress" default:"tcp://0.0.0.0:22000"`
|
||||||
|
GlobalAnnServers []string `xml:"globalAnnounceServer" json:"globalAnnounceServers" json:"globalAnnounceServer" default:"default"`
|
||||||
|
GlobalAnnEnabled bool `xml:"globalAnnounceEnabled" json:"globalAnnounceEnabled" default:"true"`
|
||||||
|
LocalAnnEnabled bool `xml:"localAnnounceEnabled" json:"localAnnounceEnabled" default:"true"`
|
||||||
|
LocalAnnPort int `xml:"localAnnouncePort" json:"localAnnouncePort" default:"21027"`
|
||||||
|
LocalAnnMCAddr string `xml:"localAnnounceMCAddr" json:"localAnnounceMCAddr" default:"[ff12::8384]:21027"`
|
||||||
|
RelayServers []string `xml:"relayServer" json:"relayServers" default:"dynamic+https://relays.syncthing.net/endpoint"`
|
||||||
|
MaxSendKbps int `xml:"maxSendKbps" json:"maxSendKbps"`
|
||||||
|
MaxRecvKbps int `xml:"maxRecvKbps" json:"maxRecvKbps"`
|
||||||
|
ReconnectIntervalS int `xml:"reconnectionIntervalS" json:"reconnectionIntervalS" default:"60"`
|
||||||
|
RelaysEnabled bool `xml:"relaysEnabled" json:"relaysEnabled" default:"true"`
|
||||||
|
RelayReconnectIntervalM int `xml:"relayReconnectIntervalM" json:"relayReconnectIntervalM" default:"10"`
|
||||||
|
RelayWithoutGlobalAnn bool `xml:"relayWithoutGlobalAnn" json:"relayWithoutGlobalAnn" default:"false"`
|
||||||
|
StartBrowser bool `xml:"startBrowser" json:"startBrowser" default:"true"`
|
||||||
|
UPnPEnabled bool `xml:"upnpEnabled" json:"upnpEnabled" default:"true"`
|
||||||
|
UPnPLeaseM int `xml:"upnpLeaseMinutes" json:"upnpLeaseMinutes" default:"60"`
|
||||||
|
UPnPRenewalM int `xml:"upnpRenewalMinutes" json:"upnpRenewalMinutes" default:"30"`
|
||||||
|
UPnPTimeoutS int `xml:"upnpTimeoutSeconds" json:"upnpTimeoutSeconds" default:"10"`
|
||||||
|
URAccepted int `xml:"urAccepted" json:"urAccepted"` // Accepted usage reporting version; 0 for off (undecided), -1 for off (permanently)
|
||||||
|
URUniqueID string `xml:"urUniqueID" json:"urUniqueId"` // Unique ID for reporting purposes, regenerated when UR is turned on.
|
||||||
|
URURL string `xml:"urURL" json:"urURL" default:"https://data.syncthing.net/newdata"`
|
||||||
|
URPostInsecurely bool `xml:"urPostInsecurely" json:"urPostInsecurely" default:"false"` // For testing
|
||||||
|
URInitialDelayS int `xml:"urInitialDelayS" json:"urInitialDelayS" default:"1800"`
|
||||||
|
RestartOnWakeup bool `xml:"restartOnWakeup" json:"restartOnWakeup" default:"true"`
|
||||||
|
AutoUpgradeIntervalH int `xml:"autoUpgradeIntervalH" json:"autoUpgradeIntervalH" default:"12"` // 0 for off
|
||||||
|
KeepTemporariesH int `xml:"keepTemporariesH" json:"keepTemporariesH" default:"24"` // 0 for off
|
||||||
|
CacheIgnoredFiles bool `xml:"cacheIgnoredFiles" json:"cacheIgnoredFiles" default:"true"`
|
||||||
|
ProgressUpdateIntervalS int `xml:"progressUpdateIntervalS" json:"progressUpdateIntervalS" default:"5"`
|
||||||
|
SymlinksEnabled bool `xml:"symlinksEnabled" json:"symlinksEnabled" default:"true"`
|
||||||
|
LimitBandwidthInLan bool `xml:"limitBandwidthInLan" json:"limitBandwidthInLan" default:"false"`
|
||||||
|
DatabaseBlockCacheMiB int `xml:"databaseBlockCacheMiB" json:"databaseBlockCacheMiB" default:"0"`
|
||||||
|
MinHomeDiskFreePct float64 `xml:"minHomeDiskFreePct" json:"minHomeDiskFreePct" default:"1"`
|
||||||
|
ReleasesURL string `xml:"releasesURL" json:"releasesURL" default:"https://api.github.com/repos/syncthing/syncthing/releases?per_page=30"`
|
||||||
|
AlwaysLocalNets []string `xml:"alwaysLocalNet" json:"alwaysLocalNets"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (orig OptionsConfiguration) Copy() OptionsConfiguration {
|
||||||
|
c := orig
|
||||||
|
c.ListenAddress = make([]string, len(orig.ListenAddress))
|
||||||
|
copy(c.ListenAddress, orig.ListenAddress)
|
||||||
|
c.GlobalAnnServers = make([]string, len(orig.GlobalAnnServers))
|
||||||
|
copy(c.GlobalAnnServers, orig.GlobalAnnServers)
|
||||||
|
return c
|
||||||
|
}
|
61
lib/config/pulorder.go
Normal file
61
lib/config/pulorder.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (C) 2014 The Syncthing Authors.
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
type PullOrder int
|
||||||
|
|
||||||
|
const (
|
||||||
|
OrderRandom PullOrder = iota // default is random
|
||||||
|
OrderAlphabetic
|
||||||
|
OrderSmallestFirst
|
||||||
|
OrderLargestFirst
|
||||||
|
OrderOldestFirst
|
||||||
|
OrderNewestFirst
|
||||||
|
)
|
||||||
|
|
||||||
|
func (o PullOrder) String() string {
|
||||||
|
switch o {
|
||||||
|
case OrderRandom:
|
||||||
|
return "random"
|
||||||
|
case OrderAlphabetic:
|
||||||
|
return "alphabetic"
|
||||||
|
case OrderSmallestFirst:
|
||||||
|
return "smallestFirst"
|
||||||
|
case OrderLargestFirst:
|
||||||
|
return "largestFirst"
|
||||||
|
case OrderOldestFirst:
|
||||||
|
return "oldestFirst"
|
||||||
|
case OrderNewestFirst:
|
||||||
|
return "newestFirst"
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o PullOrder) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(o.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *PullOrder) UnmarshalText(bs []byte) error {
|
||||||
|
switch string(bs) {
|
||||||
|
case "random":
|
||||||
|
*o = OrderRandom
|
||||||
|
case "alphabetic":
|
||||||
|
*o = OrderAlphabetic
|
||||||
|
case "smallestFirst":
|
||||||
|
*o = OrderSmallestFirst
|
||||||
|
case "largestFirst":
|
||||||
|
*o = OrderLargestFirst
|
||||||
|
case "oldestFirst":
|
||||||
|
*o = OrderOldestFirst
|
||||||
|
case "newestFirst":
|
||||||
|
*o = OrderNewestFirst
|
||||||
|
default:
|
||||||
|
*o = OrderRandom
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
50
lib/config/versioningconfiguration.go
Normal file
50
lib/config/versioningconfiguration.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (C) 2014 The Syncthing Authors.
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import "encoding/xml"
|
||||||
|
|
||||||
|
type VersioningConfiguration struct {
|
||||||
|
Type string `xml:"type,attr" json:"type"`
|
||||||
|
Params map[string]string `json:"params"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InternalVersioningConfiguration struct {
|
||||||
|
Type string `xml:"type,attr,omitempty"`
|
||||||
|
Params []InternalParam `xml:"param"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InternalParam struct {
|
||||||
|
Key string `xml:"key,attr"`
|
||||||
|
Val string `xml:"val,attr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *VersioningConfiguration) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||||
|
var tmp InternalVersioningConfiguration
|
||||||
|
tmp.Type = c.Type
|
||||||
|
for k, v := range c.Params {
|
||||||
|
tmp.Params = append(tmp.Params, InternalParam{k, v})
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.EncodeElement(tmp, start)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *VersioningConfiguration) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||||
|
var tmp InternalVersioningConfiguration
|
||||||
|
err := d.DecodeElement(&tmp, &start)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Type = tmp.Type
|
||||||
|
c.Params = make(map[string]string, len(tmp.Params))
|
||||||
|
for _, p := range tmp.Params {
|
||||||
|
c.Params[p.Key] = p.Val
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user