Merge branch 'main' into v2
* main: fix(gui): fix previous commit fix(gui): mark unseen disconnected devices as inactive (#10048) fix(strings): differentiate setup(n) and set(v) up (#10024) chore(fs): changes to allow Filesystem to be implemented externally (#10040) chore(config): resolve primary STUN servers via SRV record (fixes #10029) (#10031) build: push artifacts to Azure (#10044) chore(gui, man, authors): update docs, translations, and contributors
This commit is contained in:
@@ -68,13 +68,9 @@ var (
|
||||
DefaultTheme = "default"
|
||||
// Default stun servers should be substituted when the configuration
|
||||
// contains <stunServer>default</stunServer>.
|
||||
|
||||
// DefaultPrimaryStunServers are servers provided by us (to avoid causing the public servers burden)
|
||||
DefaultPrimaryStunServers = []string{
|
||||
// Discontinued because of misuse. See https://forum.syncthing.net/t/stun-server-misuse/23319
|
||||
//"stun.syncthing.net:3478",
|
||||
}
|
||||
DefaultSecondaryStunServers = []string{
|
||||
// The primary stun servers are provided by us and are resolved via an SRV record
|
||||
// The fallback stun servers are used if the primary ones can't be resolved or are down.
|
||||
DefaultFallbackStunServers = []string{
|
||||
"stun.counterpath.com:3478",
|
||||
"stun.counterpath.net:3478",
|
||||
"stun.ekiga.net:3478",
|
||||
|
||||
@@ -8,8 +8,10 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/rand"
|
||||
@@ -183,15 +185,22 @@ func (opts OptionsConfiguration) StunServers() []string {
|
||||
for _, addr := range opts.RawStunServers {
|
||||
switch addr {
|
||||
case "default":
|
||||
defaultPrimaryAddresses := make([]string, len(DefaultPrimaryStunServers))
|
||||
copy(defaultPrimaryAddresses, DefaultPrimaryStunServers)
|
||||
rand.Shuffle(defaultPrimaryAddresses)
|
||||
addresses = append(addresses, defaultPrimaryAddresses...)
|
||||
_, records, err := net.LookupSRV("stun", "udp", "syncthing.net")
|
||||
if err != nil {
|
||||
l.Warnln("Unable to resolve primary STUN servers via DNS:", err)
|
||||
}
|
||||
|
||||
defaultSecondaryAddresses := make([]string, len(DefaultSecondaryStunServers))
|
||||
copy(defaultSecondaryAddresses, DefaultSecondaryStunServers)
|
||||
rand.Shuffle(defaultSecondaryAddresses)
|
||||
addresses = append(addresses, defaultSecondaryAddresses...)
|
||||
for _, record := range records {
|
||||
priority := record.Priority
|
||||
target := strings.TrimSuffix(record.Target, ".")
|
||||
address := fmt.Sprintf("%s:%d", target, record.Port)
|
||||
l.Debugf("Resolved primary STUN server %s with priority %d", address, priority)
|
||||
addresses = append(addresses, address)
|
||||
}
|
||||
|
||||
fallbackAddresses := slices.Clone(DefaultFallbackStunServers)
|
||||
rand.Shuffle(fallbackAddresses)
|
||||
addresses = append(addresses, fallbackAddresses...)
|
||||
default:
|
||||
addresses = append(addresses, addr)
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func init() {
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
// Defer this, so that logging gets setup.
|
||||
// Defer this, so that logging gets set up.
|
||||
go func() {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
l.Infoln("Proxy settings detected")
|
||||
|
||||
@@ -336,10 +336,6 @@ func (*BasicFilesystem) underlying() (Filesystem, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (*BasicFilesystem) wrapperType() filesystemWrapperType {
|
||||
return filesystemWrapperTypeNone
|
||||
}
|
||||
|
||||
// basicFile implements the fs.File interface on top of an os.File
|
||||
type basicFile struct {
|
||||
*os.File
|
||||
|
||||
@@ -54,7 +54,7 @@ func (f *BasicFilesystem) Watch(name string, ignore Matcher, ctx context.Context
|
||||
if err != nil {
|
||||
notify.Stop(backendChan)
|
||||
if reachedMaxUserWatches(err) {
|
||||
err = errors.New("failed to setup inotify handler. Please increase inotify limits, see https://docs.syncthing.net/users/faq.html#inotify-limits")
|
||||
err = errors.New("failed to set up inotify handler. Please increase inotify limits, see https://docs.syncthing.net/users/faq.html#inotify-limits")
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -357,10 +357,6 @@ func (f *caseFilesystem) underlying() (Filesystem, bool) {
|
||||
return f.Filesystem, true
|
||||
}
|
||||
|
||||
func (*caseFilesystem) wrapperType() filesystemWrapperType {
|
||||
return filesystemWrapperTypeCase
|
||||
}
|
||||
|
||||
func (f *caseFilesystem) checkCase(name string) error {
|
||||
var err error
|
||||
if name, err = Canonicalize(name); err != nil {
|
||||
|
||||
+13
-9
@@ -161,10 +161,11 @@ func BenchmarkWalkCaseFakeFS100k(b *testing.B) {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.Run("rawfs", func(b *testing.B) {
|
||||
var fakefs *fakeFS
|
||||
if ffs, ok := unwrapFilesystem(fsys, filesystemWrapperTypeNone); ok {
|
||||
fakefs = ffs.(*fakeFS)
|
||||
fakefs, ok := unwrapFilesystem[*fakeFS](fsys)
|
||||
if !ok {
|
||||
panic("expected unwrap to fakefs")
|
||||
}
|
||||
|
||||
fakefs.resetCounters()
|
||||
benchmarkWalkFakeFS(b, fsys, paths, 0, "")
|
||||
fakefs.reportMetricsPerOp(b)
|
||||
@@ -180,9 +181,10 @@ func BenchmarkWalkCaseFakeFS100k(b *testing.B) {
|
||||
cache: newCaseCache(),
|
||||
},
|
||||
}
|
||||
var fakefs *fakeFS
|
||||
if ffs, ok := unwrapFilesystem(fsys, filesystemWrapperTypeNone); ok {
|
||||
fakefs = ffs.(*fakeFS)
|
||||
|
||||
fakefs, ok := unwrapFilesystem[*fakeFS](fsys)
|
||||
if !ok {
|
||||
panic("expected unwrap to fakefs")
|
||||
}
|
||||
fakefs.resetCounters()
|
||||
benchmarkWalkFakeFS(b, casefs, paths, 0, "")
|
||||
@@ -209,10 +211,12 @@ func BenchmarkWalkCaseFakeFS100k(b *testing.B) {
|
||||
cache: newCaseCache(),
|
||||
},
|
||||
}
|
||||
var fakefs *fakeFS
|
||||
if ffs, ok := unwrapFilesystem(fsys, filesystemWrapperTypeNone); ok {
|
||||
fakefs = ffs.(*fakeFS)
|
||||
|
||||
fakefs, ok := unwrapFilesystem[*fakeFS](fsys)
|
||||
if !ok {
|
||||
panic("expected unwrap to fakefs")
|
||||
}
|
||||
|
||||
fakefs.resetCounters()
|
||||
benchmarkWalkFakeFS(b, casefs, paths, otherOpEvery, otherOpPath)
|
||||
fakefs.reportMetricsPerOp(b)
|
||||
|
||||
@@ -69,7 +69,3 @@ func (fs *errorFilesystem) PlatformData(_ string, _, _ bool, _ XattrFilter) (pro
|
||||
func (*errorFilesystem) underlying() (Filesystem, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (*errorFilesystem) wrapperType() filesystemWrapperType {
|
||||
return filesystemWrapperTypeError
|
||||
}
|
||||
|
||||
@@ -724,10 +724,6 @@ func (*fakeFS) underlying() (Filesystem, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (*fakeFS) wrapperType() filesystemWrapperType {
|
||||
return filesystemWrapperTypeNone
|
||||
}
|
||||
|
||||
func (fs *fakeFS) resetCounters() {
|
||||
fs.mut.Lock()
|
||||
fs.counters = fakeFSCounters{}
|
||||
|
||||
+16
-20
@@ -21,18 +21,6 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
)
|
||||
|
||||
type filesystemWrapperType int32
|
||||
|
||||
const (
|
||||
filesystemWrapperTypeNone filesystemWrapperType = iota
|
||||
filesystemWrapperTypeMtime
|
||||
filesystemWrapperTypeCase
|
||||
filesystemWrapperTypeError
|
||||
filesystemWrapperTypeWalk
|
||||
filesystemWrapperTypeLog
|
||||
filesystemWrapperTypeMetrics
|
||||
)
|
||||
|
||||
type XattrFilter interface {
|
||||
Permit(string) bool
|
||||
GetMaxSingleEntrySize() int
|
||||
@@ -75,10 +63,11 @@ type Filesystem interface {
|
||||
PlatformData(name string, withOwnership, withXattrs bool, xattrFilter XattrFilter) (protocol.PlatformData, error)
|
||||
GetXattr(name string, xattrFilter XattrFilter) ([]protocol.Xattr, error)
|
||||
SetXattr(path string, xattrs []protocol.Xattr, xattrFilter XattrFilter) error
|
||||
}
|
||||
|
||||
type wrappingFilesystem interface {
|
||||
// Used for unwrapping things
|
||||
underlying() (Filesystem, bool)
|
||||
wrapperType() filesystemWrapperType
|
||||
}
|
||||
|
||||
// The File interface abstracts access to a regular file, being a somewhat
|
||||
@@ -353,16 +342,23 @@ func Canonicalize(file string) (string, error) {
|
||||
return file, nil
|
||||
}
|
||||
|
||||
// unwrapFilesystem removes "wrapping" filesystems to expose the filesystem of the requested wrapperType, if it exists.
|
||||
func unwrapFilesystem(fs Filesystem, wrapperType filesystemWrapperType) (Filesystem, bool) {
|
||||
var ok bool
|
||||
// unwrapFilesystem removes "wrapping" filesystems to expose the filesystem of the requested wrapper type T, if it exists.
|
||||
func unwrapFilesystem[T Filesystem](fs Filesystem) (T, bool) {
|
||||
for {
|
||||
if fs.wrapperType() == wrapperType {
|
||||
return fs, true
|
||||
if unwrapped, ok := fs.(T); ok {
|
||||
return unwrapped, true
|
||||
}
|
||||
fs, ok = fs.underlying()
|
||||
|
||||
wrappingFs, ok := fs.(wrappingFilesystem)
|
||||
if !ok {
|
||||
return nil, false
|
||||
var x T
|
||||
return x, false
|
||||
}
|
||||
|
||||
fs, ok = wrappingFs.underlying()
|
||||
if !ok {
|
||||
var x T
|
||||
return x, false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +177,3 @@ func (fs *logFilesystem) Usage(name string) (Usage, error) {
|
||||
func (fs *logFilesystem) underlying() (Filesystem, bool) {
|
||||
return fs.Filesystem, true
|
||||
}
|
||||
|
||||
func (*logFilesystem) wrapperType() filesystemWrapperType {
|
||||
return filesystemWrapperTypeLog
|
||||
}
|
||||
|
||||
@@ -273,10 +273,6 @@ func (m *metricsFS) underlying() (Filesystem, bool) {
|
||||
return m.next, true
|
||||
}
|
||||
|
||||
func (m *metricsFS) wrapperType() filesystemWrapperType {
|
||||
return filesystemWrapperTypeMetrics
|
||||
}
|
||||
|
||||
type metricsFile struct {
|
||||
fs *metricsFS
|
||||
next File
|
||||
|
||||
+1
-5
@@ -143,10 +143,6 @@ func (f *mtimeFS) underlying() (Filesystem, bool) {
|
||||
return f.Filesystem, true
|
||||
}
|
||||
|
||||
func (*mtimeFS) wrapperType() filesystemWrapperType {
|
||||
return filesystemWrapperTypeMtime
|
||||
}
|
||||
|
||||
func (f *mtimeFS) save(name string, ondisk, virtual time.Time) {
|
||||
if f.caseInsensitive {
|
||||
name = UnicodeLowercaseNormalized(name)
|
||||
@@ -209,7 +205,7 @@ func (f mtimeFile) unwrap() File {
|
||||
}
|
||||
|
||||
func GetMtimeMapping(fs Filesystem, file string) (ondisk, virtual time.Time) {
|
||||
fs, ok := unwrapFilesystem(fs, filesystemWrapperTypeMtime)
|
||||
fs, ok := unwrapFilesystem[*mtimeFS](fs)
|
||||
if !ok {
|
||||
return time.Time{}, time.Time{}
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ func newMtimeFS(path string, db database, options ...MtimeFSOption) *mtimeFS {
|
||||
|
||||
func newMtimeFSWithWalk(path string, db database, options ...MtimeFSOption) (*mtimeFS, *walkFilesystem) {
|
||||
fs := NewFilesystem(FilesystemTypeBasic, path, NewMtimeOption(db, "", options...))
|
||||
wfs, _ := unwrapFilesystem(fs, filesystemWrapperTypeWalk)
|
||||
mfs, _ := unwrapFilesystem(fs, filesystemWrapperTypeMtime)
|
||||
return mfs.(*mtimeFS), wfs.(*walkFilesystem)
|
||||
wfs, _ := unwrapFilesystem[*walkFilesystem](fs)
|
||||
mfs, _ := unwrapFilesystem[*mtimeFS](fs)
|
||||
return mfs, wfs
|
||||
}
|
||||
|
||||
@@ -153,7 +153,3 @@ func (f *walkFilesystem) Walk(root string, walkFn WalkFunc) error {
|
||||
func (f *walkFilesystem) underlying() (Filesystem, bool) {
|
||||
return f.Filesystem, true
|
||||
}
|
||||
|
||||
func (*walkFilesystem) wrapperType() filesystemWrapperType {
|
||||
return filesystemWrapperTypeWalk
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ func TestClusterConfigFirst(t *testing.T) {
|
||||
case c.outbox <- asyncMessage{&bep.Ping{}, nil}:
|
||||
t.Fatal("able to send ping before cluster config")
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
// Allow some time for c.writerLoop to setup after c.Start
|
||||
// Allow some time for c.writerLoop to set up after c.Start
|
||||
}
|
||||
|
||||
c.ClusterConfig(&ClusterConfig{})
|
||||
|
||||
@@ -268,7 +268,7 @@ func (a *App) startup() error {
|
||||
|
||||
// Chicken and egg, discovery manager depends on connection service to tell it what addresses it's listening on
|
||||
// Connection service depends on discovery manager to get addresses to connect to.
|
||||
// Create a wrapper that is then wired after they are both setup.
|
||||
// Create a wrapper that is then wired after they are both set up.
|
||||
addrLister := &lateAddressLister{}
|
||||
|
||||
connRegistry := registry.New()
|
||||
|
||||
Reference in New Issue
Block a user