parent
f6f696c6c5
commit
b1c74860e8
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/syncthing/syncthing/lib/build"
|
"github.com/syncthing/syncthing/lib/build"
|
||||||
"github.com/syncthing/syncthing/lib/config"
|
"github.com/syncthing/syncthing/lib/config"
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/locations"
|
"github.com/syncthing/syncthing/lib/locations"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
@ -85,7 +86,7 @@ func main() {
|
|||||||
myID := protocol.NewDeviceID(cert.Certificate[0])
|
myID := protocol.NewDeviceID(cert.Certificate[0])
|
||||||
|
|
||||||
// Load the config
|
// Load the config
|
||||||
cfg, err := config.Load(locations.Get(locations.ConfigFile), myID)
|
cfg, err := config.Load(locations.Get(locations.ConfigFile), myID, events.NoopLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(errors.Wrap(err, "loading config"))
|
log.Fatalln(errors.Wrap(err, "loading config"))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import (
|
|||||||
|
|
||||||
"github.com/syncthing/syncthing/lib/config"
|
"github.com/syncthing/syncthing/lib/config"
|
||||||
"github.com/syncthing/syncthing/lib/discover"
|
"github.com/syncthing/syncthing/lib/discover"
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -82,7 +83,7 @@ func checkServers(deviceID protocol.DeviceID, servers ...string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkServer(deviceID protocol.DeviceID, server string) checkResult {
|
func checkServer(deviceID protocol.DeviceID, server string) checkResult {
|
||||||
disco, err := discover.NewGlobal(server, tls.Certificate{}, nil)
|
disco, err := discover.NewGlobal(server, tls.Certificate{}, nil, events.NoopLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return checkResult{error: err}
|
return checkResult{error: err}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/osutil"
|
"github.com/syncthing/syncthing/lib/osutil"
|
||||||
"github.com/syncthing/syncthing/lib/relay/protocol"
|
"github.com/syncthing/syncthing/lib/relay/protocol"
|
||||||
"github.com/syncthing/syncthing/lib/tlsutil"
|
"github.com/syncthing/syncthing/lib/tlsutil"
|
||||||
@ -194,7 +195,7 @@ func main() {
|
|||||||
log.Println("ID:", id)
|
log.Println("ID:", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapper := config.Wrap("config", config.New(id))
|
wrapper := config.Wrap("config", config.New(id), events.NoopLogger)
|
||||||
wrapper.SetOptions(config.OptionsConfiguration{
|
wrapper.SetOptions(config.OptionsConfiguration{
|
||||||
NATLeaseM: natLease,
|
NATLeaseM: natLease,
|
||||||
NATRenewalM: natRenewal,
|
NATRenewalM: natRenewal,
|
||||||
|
|||||||
@ -394,7 +394,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func openGUI(myID protocol.DeviceID) error {
|
func openGUI(myID protocol.DeviceID) error {
|
||||||
cfg, err := loadOrDefaultConfig(myID)
|
cfg, err := loadOrDefaultConfig(myID, events.NoopLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -437,7 +437,7 @@ func generate(generateDir string) error {
|
|||||||
l.Warnln("Config exists; will not overwrite.")
|
l.Warnln("Config exists; will not overwrite.")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
cfg, err := syncthing.DefaultConfig(cfgFile, myID, noDefaultFolder)
|
cfg, err := syncthing.DefaultConfig(cfgFile, myID, events.NoopLogger, noDefaultFolder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -471,7 +471,7 @@ func debugFacilities() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkUpgrade() upgrade.Release {
|
func checkUpgrade() upgrade.Release {
|
||||||
cfg, _ := loadOrDefaultConfig(protocol.EmptyDeviceID)
|
cfg, _ := loadOrDefaultConfig(protocol.EmptyDeviceID, events.NoopLogger)
|
||||||
opts := cfg.Options()
|
opts := cfg.Options()
|
||||||
release, err := upgrade.LatestRelease(opts.ReleasesURL, build.Version, opts.UpgradeToPreReleases)
|
release, err := upgrade.LatestRelease(opts.ReleasesURL, build.Version, opts.UpgradeToPreReleases)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -512,7 +512,7 @@ func performUpgrade(release upgrade.Release) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func upgradeViaRest() error {
|
func upgradeViaRest() error {
|
||||||
cfg, _ := loadOrDefaultConfig(protocol.EmptyDeviceID)
|
cfg, _ := loadOrDefaultConfig(protocol.EmptyDeviceID, events.NoopLogger)
|
||||||
u, err := url.Parse(cfg.GUI().URL())
|
u, err := url.Parse(cfg.GUI().URL())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -566,7 +566,11 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := syncthing.LoadConfigAtStartup(locations.Get(locations.ConfigFile), cert, runtimeOptions.allowNewerConfig, noDefaultFolder)
|
evLogger := events.NewLogger()
|
||||||
|
go evLogger.Serve()
|
||||||
|
defer evLogger.Stop()
|
||||||
|
|
||||||
|
cfg, err := syncthing.LoadConfigAtStartup(locations.Get(locations.ConfigFile), cert, evLogger, runtimeOptions.allowNewerConfig, noDefaultFolder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Warnln("Failed to initialize config:", err)
|
l.Warnln("Failed to initialize config:", err)
|
||||||
os.Exit(exitError)
|
os.Exit(exitError)
|
||||||
@ -594,7 +598,7 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
|
|||||||
appOpts.DeadlockTimeoutS = secs
|
appOpts.DeadlockTimeoutS = secs
|
||||||
}
|
}
|
||||||
|
|
||||||
app := syncthing.New(cfg, ldb, cert, appOpts)
|
app := syncthing.New(cfg, ldb, evLogger, cert, appOpts)
|
||||||
|
|
||||||
setupSignalHandling(app)
|
setupSignalHandling(app)
|
||||||
|
|
||||||
@ -639,7 +643,7 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
|
|||||||
if runtimeOptions.NoUpgrade {
|
if runtimeOptions.NoUpgrade {
|
||||||
l.Infof("No automatic upgrades; STNOUPGRADE environment variable defined.")
|
l.Infof("No automatic upgrades; STNOUPGRADE environment variable defined.")
|
||||||
} else {
|
} else {
|
||||||
go autoUpgrade(cfg, app)
|
go autoUpgrade(cfg, app, evLogger)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -684,12 +688,12 @@ func setupSignalHandling(app *syncthing.App) {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadOrDefaultConfig(myID protocol.DeviceID) (config.Wrapper, error) {
|
func loadOrDefaultConfig(myID protocol.DeviceID, evLogger events.Logger) (config.Wrapper, error) {
|
||||||
cfgFile := locations.Get(locations.ConfigFile)
|
cfgFile := locations.Get(locations.ConfigFile)
|
||||||
cfg, err := config.Load(cfgFile, myID)
|
cfg, err := config.Load(cfgFile, myID, evLogger)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cfg, err = syncthing.DefaultConfig(cfgFile, myID, noDefaultFolder)
|
cfg, err = syncthing.DefaultConfig(cfgFile, myID, evLogger, noDefaultFolder)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cfg, err
|
return cfg, err
|
||||||
@ -774,9 +778,9 @@ func standbyMonitor(app *syncthing.App) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func autoUpgrade(cfg config.Wrapper, app *syncthing.App) {
|
func autoUpgrade(cfg config.Wrapper, app *syncthing.App, evLogger events.Logger) {
|
||||||
timer := time.NewTimer(0)
|
timer := time.NewTimer(0)
|
||||||
sub := events.Default.Subscribe(events.DeviceConnected)
|
sub := evLogger.Subscribe(events.DeviceConnected)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case event := <-sub.C():
|
case event := <-sub.C():
|
||||||
@ -798,7 +802,7 @@ func autoUpgrade(cfg config.Wrapper, app *syncthing.App) {
|
|||||||
|
|
||||||
rel, err := upgrade.LatestRelease(opts.ReleasesURL, build.Version, opts.UpgradeToPreReleases)
|
rel, err := upgrade.LatestRelease(opts.ReleasesURL, build.Version, opts.UpgradeToPreReleases)
|
||||||
if err == upgrade.ErrUpgradeUnsupported {
|
if err == upgrade.ErrUpgradeUnsupported {
|
||||||
events.Default.Unsubscribe(sub)
|
sub.Unsubscribe()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -822,7 +826,7 @@ func autoUpgrade(cfg config.Wrapper, app *syncthing.App) {
|
|||||||
timer.Reset(checkInterval)
|
timer.Reset(checkInterval)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
events.Default.Unsubscribe(sub)
|
sub.Unsubscribe()
|
||||||
l.Warnf("Automatically upgraded to version %q. Restarting in 1 minute.", rel.Tag)
|
l.Warnf("Automatically upgraded to version %q. Restarting in 1 minute.", rel.Tag)
|
||||||
time.Sleep(time.Minute)
|
time.Sleep(time.Minute)
|
||||||
app.Stop(syncthing.ExitUpgrade)
|
app.Stop(syncthing.ExitUpgrade)
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/locations"
|
"github.com/syncthing/syncthing/lib/locations"
|
||||||
"github.com/syncthing/syncthing/lib/osutil"
|
"github.com/syncthing/syncthing/lib/osutil"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
@ -450,7 +451,7 @@ func childEnv() []string {
|
|||||||
// panicUploadMaxWait uploading panics...
|
// panicUploadMaxWait uploading panics...
|
||||||
func maybeReportPanics() {
|
func maybeReportPanics() {
|
||||||
// Try to get a config to see if/where panics should be reported.
|
// Try to get a config to see if/where panics should be reported.
|
||||||
cfg, err := loadOrDefaultConfig(protocol.EmptyDeviceID)
|
cfg, err := loadOrDefaultConfig(protocol.EmptyDeviceID, events.NoopLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Warnln("Couldn't load config; not reporting crash")
|
l.Warnln("Couldn't load config; not reporting crash")
|
||||||
return
|
return
|
||||||
|
|||||||
@ -71,6 +71,7 @@ type service struct {
|
|||||||
model model.Model
|
model model.Model
|
||||||
eventSubs map[events.EventType]events.BufferedSubscription
|
eventSubs map[events.EventType]events.BufferedSubscription
|
||||||
eventSubsMut sync.Mutex
|
eventSubsMut sync.Mutex
|
||||||
|
evLogger events.Logger
|
||||||
discoverer discover.CachingMux
|
discoverer discover.CachingMux
|
||||||
connectionsService connections.Service
|
connectionsService connections.Service
|
||||||
fss model.FolderSummaryService
|
fss model.FolderSummaryService
|
||||||
@ -105,7 +106,7 @@ type Service interface {
|
|||||||
WaitForStart() error
|
WaitForStart() error
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(id protocol.DeviceID, cfg config.Wrapper, assetDir, tlsDefaultCommonName string, m model.Model, defaultSub, diskSub events.BufferedSubscription, discoverer discover.CachingMux, connectionsService connections.Service, urService *ur.Service, fss model.FolderSummaryService, errors, systemLog logger.Recorder, cpu Rater, contr Controller, noUpgrade bool) Service {
|
func New(id protocol.DeviceID, cfg config.Wrapper, assetDir, tlsDefaultCommonName string, m model.Model, defaultSub, diskSub events.BufferedSubscription, evLogger events.Logger, discoverer discover.CachingMux, connectionsService connections.Service, urService *ur.Service, fss model.FolderSummaryService, errors, systemLog logger.Recorder, cpu Rater, contr Controller, noUpgrade bool) Service {
|
||||||
s := &service{
|
s := &service{
|
||||||
id: id,
|
id: id,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
@ -116,6 +117,7 @@ func New(id protocol.DeviceID, cfg config.Wrapper, assetDir, tlsDefaultCommonNam
|
|||||||
DiskEventMask: diskSub,
|
DiskEventMask: diskSub,
|
||||||
},
|
},
|
||||||
eventSubsMut: sync.NewMutex(),
|
eventSubsMut: sync.NewMutex(),
|
||||||
|
evLogger: evLogger,
|
||||||
discoverer: discoverer,
|
discoverer: discoverer,
|
||||||
connectionsService: connectionsService,
|
connectionsService: connectionsService,
|
||||||
fss: fss,
|
fss: fss,
|
||||||
@ -315,7 +317,7 @@ func (s *service) serve(stop chan struct{}) {
|
|||||||
|
|
||||||
// Wrap everything in basic auth, if user/password is set.
|
// Wrap everything in basic auth, if user/password is set.
|
||||||
if guiCfg.IsAuthEnabled() {
|
if guiCfg.IsAuthEnabled() {
|
||||||
handler = basicAuthAndSessionMiddleware("sessionid-"+s.id.String()[:5], guiCfg, s.cfg.LDAP(), handler)
|
handler = basicAuthAndSessionMiddleware("sessionid-"+s.id.String()[:5], guiCfg, s.cfg.LDAP(), handler, s.evLogger)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect to HTTPS if we are supposed to
|
// Redirect to HTTPS if we are supposed to
|
||||||
@ -1215,7 +1217,7 @@ func (s *service) getEventSub(mask events.EventType) events.BufferedSubscription
|
|||||||
s.eventSubsMut.Lock()
|
s.eventSubsMut.Lock()
|
||||||
bufsub, ok := s.eventSubs[mask]
|
bufsub, ok := s.eventSubs[mask]
|
||||||
if !ok {
|
if !ok {
|
||||||
evsub := events.Default.Subscribe(mask)
|
evsub := s.evLogger.Subscribe(mask)
|
||||||
bufsub = events.NewBufferedSubscription(evsub, EventSubBufferSize)
|
bufsub = events.NewBufferedSubscription(evsub, EventSubBufferSize)
|
||||||
s.eventSubs[mask] = bufsub
|
s.eventSubs[mask] = bufsub
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,14 +28,14 @@ var (
|
|||||||
sessionsMut = sync.NewMutex()
|
sessionsMut = sync.NewMutex()
|
||||||
)
|
)
|
||||||
|
|
||||||
func emitLoginAttempt(success bool, username string) {
|
func emitLoginAttempt(success bool, username string, evLogger events.Logger) {
|
||||||
events.Default.Log(events.LoginAttempt, map[string]interface{}{
|
evLogger.Log(events.LoginAttempt, map[string]interface{}{
|
||||||
"success": success,
|
"success": success,
|
||||||
"username": username,
|
"username": username,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func basicAuthAndSessionMiddleware(cookieName string, guiCfg config.GUIConfiguration, ldapCfg config.LDAPConfiguration, next http.Handler) http.Handler {
|
func basicAuthAndSessionMiddleware(cookieName string, guiCfg config.GUIConfiguration, ldapCfg config.LDAPConfiguration, next http.Handler, evLogger events.Logger) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if guiCfg.IsValidAPIKey(r.Header.Get("X-API-Key")) {
|
if guiCfg.IsValidAPIKey(r.Header.Get("X-API-Key")) {
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
@ -94,7 +94,7 @@ func basicAuthAndSessionMiddleware(cookieName string, guiCfg config.GUIConfigura
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !authOk {
|
if !authOk {
|
||||||
emitLoginAttempt(false, username)
|
emitLoginAttempt(false, username, evLogger)
|
||||||
error()
|
error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -109,7 +109,7 @@ func basicAuthAndSessionMiddleware(cookieName string, guiCfg config.GUIConfigura
|
|||||||
MaxAge: 0,
|
MaxAge: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
emitLoginAttempt(true, username)
|
emitLoginAttempt(true, username, evLogger)
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,9 +100,9 @@ func TestStopAfterBrokenConfig(t *testing.T) {
|
|||||||
RawUseTLS: false,
|
RawUseTLS: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
w := config.Wrap("/dev/null", cfg)
|
w := config.Wrap("/dev/null", cfg, events.NoopLogger)
|
||||||
|
|
||||||
srv := New(protocol.LocalDeviceID, w, "", "syncthing", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, false).(*service)
|
srv := New(protocol.LocalDeviceID, w, "", "syncthing", nil, nil, nil, events.NoopLogger, nil, nil, nil, nil, nil, nil, nil, nil, false).(*service)
|
||||||
defer os.Remove(token)
|
defer os.Remove(token)
|
||||||
srv.started = make(chan string)
|
srv.started = make(chan string)
|
||||||
|
|
||||||
@ -512,8 +512,8 @@ func startHTTP(cfg *mockedConfig) (string, error) {
|
|||||||
|
|
||||||
// Instantiate the API service
|
// Instantiate the API service
|
||||||
urService := ur.New(cfg, m, connections, false)
|
urService := ur.New(cfg, m, connections, false)
|
||||||
summaryService := model.NewFolderSummaryService(cfg, m, protocol.LocalDeviceID)
|
summaryService := model.NewFolderSummaryService(cfg, m, protocol.LocalDeviceID, events.NoopLogger)
|
||||||
svc := New(protocol.LocalDeviceID, cfg, assetDir, "syncthing", m, eventSub, diskEventSub, discoverer, connections, urService, summaryService, errorLog, systemLog, cpu, nil, false).(*service)
|
svc := New(protocol.LocalDeviceID, cfg, assetDir, "syncthing", m, eventSub, diskEventSub, events.NoopLogger, discoverer, connections, urService, summaryService, errorLog, systemLog, cpu, nil, false).(*service)
|
||||||
defer os.Remove(token)
|
defer os.Remove(token)
|
||||||
svc.started = addrChan
|
svc.started = addrChan
|
||||||
|
|
||||||
@ -979,7 +979,7 @@ func TestEventMasks(t *testing.T) {
|
|||||||
cfg := new(mockedConfig)
|
cfg := new(mockedConfig)
|
||||||
defSub := new(mockedEventSub)
|
defSub := new(mockedEventSub)
|
||||||
diskSub := new(mockedEventSub)
|
diskSub := new(mockedEventSub)
|
||||||
svc := New(protocol.LocalDeviceID, cfg, "", "syncthing", nil, defSub, diskSub, nil, nil, nil, nil, nil, nil, nil, nil, false).(*service)
|
svc := New(protocol.LocalDeviceID, cfg, "", "syncthing", nil, defSub, diskSub, events.NoopLogger, nil, nil, nil, nil, nil, nil, nil, nil, false).(*service)
|
||||||
defer os.Remove(token)
|
defer os.Remove(token)
|
||||||
|
|
||||||
if mask := svc.getEventMask(""); mask != DefaultEventMask {
|
if mask := svc.getEventMask(""); mask != DefaultEventMask {
|
||||||
|
|||||||
@ -44,7 +44,7 @@ func (validationError) String() string {
|
|||||||
func TestReplaceCommit(t *testing.T) {
|
func TestReplaceCommit(t *testing.T) {
|
||||||
t.Skip("broken, fails randomly, #3834")
|
t.Skip("broken, fails randomly, #3834")
|
||||||
|
|
||||||
w := Wrap("/dev/null", Configuration{Version: 0})
|
w := wrap("/dev/null", Configuration{Version: 0})
|
||||||
if w.RawCopy().Version != 0 {
|
if w.RawCopy().Version != 0 {
|
||||||
t.Fatal("Config incorrect")
|
t.Fatal("Config incorrect")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/d4l3k/messagediff"
|
"github.com/d4l3k/messagediff"
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/fs"
|
"github.com/syncthing/syncthing/lib/fs"
|
||||||
"github.com/syncthing/syncthing/lib/osutil"
|
"github.com/syncthing/syncthing/lib/osutil"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
@ -86,7 +87,7 @@ func TestDefaultValues(t *testing.T) {
|
|||||||
func TestDeviceConfig(t *testing.T) {
|
func TestDeviceConfig(t *testing.T) {
|
||||||
for i := OldestHandledVersion; i <= CurrentVersion; i++ {
|
for i := OldestHandledVersion; i <= CurrentVersion; i++ {
|
||||||
os.RemoveAll(filepath.Join("testdata", DefaultMarkerName))
|
os.RemoveAll(filepath.Join("testdata", DefaultMarkerName))
|
||||||
wr, err := Load(fmt.Sprintf("testdata/v%d.xml", i), device1)
|
wr, err := load(fmt.Sprintf("testdata/v%d.xml", i), device1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -168,7 +169,7 @@ func TestDeviceConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNoListenAddresses(t *testing.T) {
|
func TestNoListenAddresses(t *testing.T) {
|
||||||
cfg, err := Load("testdata/nolistenaddress.xml", device1)
|
cfg, err := load("testdata/nolistenaddress.xml", device1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -225,7 +226,7 @@ func TestOverriddenValues(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
os.Unsetenv("STNOUPGRADE")
|
os.Unsetenv("STNOUPGRADE")
|
||||||
cfg, err := Load("testdata/overridenvalues.xml", device1)
|
cfg, err := load("testdata/overridenvalues.xml", device1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -270,7 +271,7 @@ func TestDeviceAddressesDynamic(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := Load("testdata/deviceaddressesdynamic.xml", device4)
|
cfg, err := load("testdata/deviceaddressesdynamic.xml", device4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -319,7 +320,7 @@ func TestDeviceCompression(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := Load("testdata/devicecompression.xml", device4)
|
cfg, err := load("testdata/devicecompression.xml", device4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -365,7 +366,7 @@ func TestDeviceAddressesStatic(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := Load("testdata/deviceaddressesstatic.xml", device4)
|
cfg, err := load("testdata/deviceaddressesstatic.xml", device4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -377,7 +378,7 @@ func TestDeviceAddressesStatic(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestVersioningConfig(t *testing.T) {
|
func TestVersioningConfig(t *testing.T) {
|
||||||
cfg, err := Load("testdata/versioningconfig.xml", device4)
|
cfg, err := load("testdata/versioningconfig.xml", device4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -404,7 +405,7 @@ func TestIssue1262(t *testing.T) {
|
|||||||
t.Skipf("path gets converted to absolute as part of the filesystem initialization on linux")
|
t.Skipf("path gets converted to absolute as part of the filesystem initialization on linux")
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := Load("testdata/issue-1262.xml", device4)
|
cfg, err := load("testdata/issue-1262.xml", device4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -418,7 +419,7 @@ func TestIssue1262(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIssue1750(t *testing.T) {
|
func TestIssue1750(t *testing.T) {
|
||||||
cfg, err := Load("testdata/issue-1750.xml", device4)
|
cfg, err := load("testdata/issue-1750.xml", device4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -520,7 +521,7 @@ func TestNewSaveLoad(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
intCfg := New(device1)
|
intCfg := New(device1)
|
||||||
cfg := Wrap(path, intCfg)
|
cfg := wrap(path, intCfg)
|
||||||
|
|
||||||
// To make the equality pass later
|
// To make the equality pass later
|
||||||
cfg.(*wrapper).cfg.XMLName.Local = "configuration"
|
cfg.(*wrapper).cfg.XMLName.Local = "configuration"
|
||||||
@ -537,7 +538,7 @@ func TestNewSaveLoad(t *testing.T) {
|
|||||||
t.Error(path, "does not exist")
|
t.Error(path, "does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg2, err := Load(path, device1)
|
cfg2, err := load(path, device1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -564,7 +565,7 @@ func TestPrepare(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCopy(t *testing.T) {
|
func TestCopy(t *testing.T) {
|
||||||
wrapper, err := Load("testdata/example.xml", device1)
|
wrapper, err := load("testdata/example.xml", device1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -603,7 +604,7 @@ func TestCopy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPullOrder(t *testing.T) {
|
func TestPullOrder(t *testing.T) {
|
||||||
wrapper, err := Load("testdata/pullorder.xml", device1)
|
wrapper, err := load("testdata/pullorder.xml", device1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -643,7 +644,7 @@ func TestPullOrder(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
wrapper = Wrap("testdata/pullorder.xml", cfg)
|
wrapper = wrap("testdata/pullorder.xml", cfg)
|
||||||
folders = wrapper.Folders()
|
folders = wrapper.Folders()
|
||||||
|
|
||||||
for _, tc := range expected {
|
for _, tc := range expected {
|
||||||
@ -654,7 +655,7 @@ func TestPullOrder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLargeRescanInterval(t *testing.T) {
|
func TestLargeRescanInterval(t *testing.T) {
|
||||||
wrapper, err := Load("testdata/largeinterval.xml", device1)
|
wrapper, err := load("testdata/largeinterval.xml", device1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -692,7 +693,7 @@ func TestGUIConfigURL(t *testing.T) {
|
|||||||
func TestDuplicateDevices(t *testing.T) {
|
func TestDuplicateDevices(t *testing.T) {
|
||||||
// Duplicate devices should be removed
|
// Duplicate devices should be removed
|
||||||
|
|
||||||
wrapper, err := Load("testdata/dupdevices.xml", device1)
|
wrapper, err := load("testdata/dupdevices.xml", device1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -710,7 +711,7 @@ func TestDuplicateDevices(t *testing.T) {
|
|||||||
func TestDuplicateFolders(t *testing.T) {
|
func TestDuplicateFolders(t *testing.T) {
|
||||||
// Duplicate folders are a loading error
|
// Duplicate folders are a loading error
|
||||||
|
|
||||||
_, err := Load("testdata/dupfolders.xml", device1)
|
_, err := load("testdata/dupfolders.xml", device1)
|
||||||
if err == nil || !strings.Contains(err.Error(), errFolderIDDuplicate.Error()) {
|
if err == nil || !strings.Contains(err.Error(), errFolderIDDuplicate.Error()) {
|
||||||
t.Fatal(`Expected error to mention "duplicate folder ID":`, err)
|
t.Fatal(`Expected error to mention "duplicate folder ID":`, err)
|
||||||
}
|
}
|
||||||
@ -721,7 +722,7 @@ func TestEmptyFolderPaths(t *testing.T) {
|
|||||||
// get messed up by the prepare steps (e.g., become the current dir or
|
// get messed up by the prepare steps (e.g., become the current dir or
|
||||||
// get a slash added so that it becomes the root directory or similar).
|
// get a slash added so that it becomes the root directory or similar).
|
||||||
|
|
||||||
_, err := Load("testdata/nopath.xml", device1)
|
_, err := load("testdata/nopath.xml", device1)
|
||||||
if err == nil || !strings.Contains(err.Error(), errFolderPathEmpty.Error()) {
|
if err == nil || !strings.Contains(err.Error(), errFolderPathEmpty.Error()) {
|
||||||
t.Fatal("Expected error due to empty folder path, got", err)
|
t.Fatal("Expected error due to empty folder path, got", err)
|
||||||
}
|
}
|
||||||
@ -790,7 +791,7 @@ func TestIgnoredDevices(t *testing.T) {
|
|||||||
// Verify that ignored devices that are also present in the
|
// Verify that ignored devices that are also present in the
|
||||||
// configuration are not in fact ignored.
|
// configuration are not in fact ignored.
|
||||||
|
|
||||||
wrapper, err := Load("testdata/ignoreddevices.xml", device1)
|
wrapper, err := load("testdata/ignoreddevices.xml", device1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -808,7 +809,7 @@ func TestIgnoredFolders(t *testing.T) {
|
|||||||
// configuration are not in fact ignored.
|
// configuration are not in fact ignored.
|
||||||
// Also, verify that folders that are shared with a device are not ignored.
|
// Also, verify that folders that are shared with a device are not ignored.
|
||||||
|
|
||||||
wrapper, err := Load("testdata/ignoredfolders.xml", device1)
|
wrapper, err := load("testdata/ignoredfolders.xml", device1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -844,7 +845,7 @@ func TestIgnoredFolders(t *testing.T) {
|
|||||||
func TestGetDevice(t *testing.T) {
|
func TestGetDevice(t *testing.T) {
|
||||||
// Verify that the Device() call does the right thing
|
// Verify that the Device() call does the right thing
|
||||||
|
|
||||||
wrapper, err := Load("testdata/ignoreddevices.xml", device1)
|
wrapper, err := load("testdata/ignoreddevices.xml", device1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -871,7 +872,7 @@ func TestGetDevice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSharesRemovedOnDeviceRemoval(t *testing.T) {
|
func TestSharesRemovedOnDeviceRemoval(t *testing.T) {
|
||||||
wrapper, err := Load("testdata/example.xml", device1)
|
wrapper, err := load("testdata/example.xml", device1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed: %s", err)
|
t.Errorf("Failed: %s", err)
|
||||||
}
|
}
|
||||||
@ -956,7 +957,7 @@ func TestIssue4219(t *testing.T) {
|
|||||||
t.Errorf("There should be three ignored folders, not %d", ignoredFolders)
|
t.Errorf("There should be three ignored folders, not %d", ignoredFolders)
|
||||||
}
|
}
|
||||||
|
|
||||||
w := Wrap("/tmp/cfg", cfg)
|
w := wrap("/tmp/cfg", cfg)
|
||||||
if !w.IgnoredFolder(device2, "t1") {
|
if !w.IgnoredFolder(device2, "t1") {
|
||||||
t.Error("Folder device2 t1 should be ignored")
|
t.Error("Folder device2 t1 should be ignored")
|
||||||
}
|
}
|
||||||
@ -1145,3 +1146,11 @@ func defaultConfigAsMap() map[string]interface{} {
|
|||||||
}
|
}
|
||||||
return tmp
|
return tmp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func load(path string, myID protocol.DeviceID) (Wrapper, error) {
|
||||||
|
return Load(path, myID, events.NoopLogger)
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrap(path string, cfg Configuration) Wrapper {
|
||||||
|
return Wrap(path, cfg, events.NoopLogger)
|
||||||
|
}
|
||||||
|
|||||||
@ -98,6 +98,7 @@ type Wrapper interface {
|
|||||||
type wrapper struct {
|
type wrapper struct {
|
||||||
cfg Configuration
|
cfg Configuration
|
||||||
path string
|
path string
|
||||||
|
evLogger events.Logger
|
||||||
|
|
||||||
deviceMap map[protocol.DeviceID]DeviceConfiguration
|
deviceMap map[protocol.DeviceID]DeviceConfiguration
|
||||||
folderMap map[string]FolderConfiguration
|
folderMap map[string]FolderConfiguration
|
||||||
@ -133,10 +134,11 @@ func (w *wrapper) StunServers() []string {
|
|||||||
|
|
||||||
// Wrap wraps an existing Configuration structure and ties it to a file on
|
// Wrap wraps an existing Configuration structure and ties it to a file on
|
||||||
// disk.
|
// disk.
|
||||||
func Wrap(path string, cfg Configuration) Wrapper {
|
func Wrap(path string, cfg Configuration, evLogger events.Logger) Wrapper {
|
||||||
w := &wrapper{
|
w := &wrapper{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
path: path,
|
path: path,
|
||||||
|
evLogger: evLogger,
|
||||||
mut: sync.NewMutex(),
|
mut: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
return w
|
return w
|
||||||
@ -144,7 +146,7 @@ func Wrap(path string, cfg Configuration) Wrapper {
|
|||||||
|
|
||||||
// Load loads an existing file on disk and returns a new configuration
|
// Load loads an existing file on disk and returns a new configuration
|
||||||
// wrapper.
|
// wrapper.
|
||||||
func Load(path string, myID protocol.DeviceID) (Wrapper, error) {
|
func Load(path string, myID protocol.DeviceID, evLogger events.Logger) (Wrapper, error) {
|
||||||
fd, err := os.Open(path)
|
fd, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -156,7 +158,7 @@ func Load(path string, myID protocol.DeviceID) (Wrapper, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return Wrap(path, cfg), nil
|
return Wrap(path, cfg, evLogger), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *wrapper) ConfigPath() string {
|
func (w *wrapper) ConfigPath() string {
|
||||||
@ -450,7 +452,7 @@ func (w *wrapper) Save() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
events.Default.Log(events.ConfigSaved, w.cfg)
|
w.evLogger.Log(events.ConfigSaved, w.cfg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/lib/config"
|
"github.com/syncthing/syncthing/lib/config"
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIsLANHost(t *testing.T) {
|
func TestIsLANHost(t *testing.T) {
|
||||||
@ -35,7 +36,7 @@ func TestIsLANHost(t *testing.T) {
|
|||||||
Options: config.OptionsConfiguration{
|
Options: config.OptionsConfiguration{
|
||||||
AlwaysLocalNets: []string{"10.20.30.0/24"},
|
AlwaysLocalNets: []string{"10.20.30.0/24"},
|
||||||
},
|
},
|
||||||
})
|
}, events.NoopLogger)
|
||||||
s := &service{cfg: cfg}
|
s := &service{cfg: cfg}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
|
|||||||
@ -8,6 +8,7 @@ package connections
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/syncthing/syncthing/lib/config"
|
"github.com/syncthing/syncthing/lib/config"
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@ -25,7 +26,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initConfig() config.Wrapper {
|
func initConfig() config.Wrapper {
|
||||||
cfg := config.Wrap("/dev/null", config.New(device1))
|
cfg := config.Wrap("/dev/null", config.New(device1), events.NoopLogger)
|
||||||
dev1Conf = config.NewDeviceConfiguration(device1, "device1")
|
dev1Conf = config.NewDeviceConfiguration(device1, "device1")
|
||||||
dev2Conf = config.NewDeviceConfiguration(device2, "device2")
|
dev2Conf = config.NewDeviceConfiguration(device2, "device2")
|
||||||
dev3Conf = config.NewDeviceConfiguration(device3, "device3")
|
dev3Conf = config.NewDeviceConfiguration(device3, "device3")
|
||||||
|
|||||||
@ -120,6 +120,7 @@ type service struct {
|
|||||||
limiter *limiter
|
limiter *limiter
|
||||||
natService *nat.Service
|
natService *nat.Service
|
||||||
natServiceToken *suture.ServiceToken
|
natServiceToken *suture.ServiceToken
|
||||||
|
evLogger events.Logger
|
||||||
|
|
||||||
listenersMut sync.RWMutex
|
listenersMut sync.RWMutex
|
||||||
listeners map[string]genericListener
|
listeners map[string]genericListener
|
||||||
@ -130,7 +131,7 @@ type service struct {
|
|||||||
connectionStatus map[string]ConnectionStatusEntry // address -> latest error/status
|
connectionStatus map[string]ConnectionStatusEntry // address -> latest error/status
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *tls.Config, discoverer discover.Finder, bepProtocolName string, tlsDefaultCommonName string) Service {
|
func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *tls.Config, discoverer discover.Finder, bepProtocolName string, tlsDefaultCommonName string, evLogger events.Logger) Service {
|
||||||
service := &service{
|
service := &service{
|
||||||
Supervisor: suture.New("connections.Service", suture.Spec{
|
Supervisor: suture.New("connections.Service", suture.Spec{
|
||||||
Log: func(line string) {
|
Log: func(line string) {
|
||||||
@ -148,6 +149,7 @@ func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *t
|
|||||||
tlsDefaultCommonName: tlsDefaultCommonName,
|
tlsDefaultCommonName: tlsDefaultCommonName,
|
||||||
limiter: newLimiter(cfg),
|
limiter: newLimiter(cfg),
|
||||||
natService: nat.NewService(myID, cfg),
|
natService: nat.NewService(myID, cfg),
|
||||||
|
evLogger: evLogger,
|
||||||
|
|
||||||
listenersMut: sync.NewRWMutex(),
|
listenersMut: sync.NewRWMutex(),
|
||||||
listeners: make(map[string]genericListener),
|
listeners: make(map[string]genericListener),
|
||||||
@ -552,7 +554,7 @@ func (s *service) createListener(factory listenerFactory, uri *url.URL) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) logListenAddressesChangedEvent(l genericListener) {
|
func (s *service) logListenAddressesChangedEvent(l genericListener) {
|
||||||
events.Default.Log(events.ListenAddressesChanged, map[string]interface{}{
|
s.evLogger.Log(events.ListenAddressesChanged, map[string]interface{}{
|
||||||
"address": l.URI(),
|
"address": l.URI(),
|
||||||
"lan": l.LANAddresses(),
|
"lan": l.LANAddresses(),
|
||||||
"wan": l.WANAddresses(),
|
"wan": l.WANAddresses(),
|
||||||
@ -579,7 +581,7 @@ func (s *service) CommitConfiguration(from, to config.Configuration) bool {
|
|||||||
|
|
||||||
s.listenersMut.Lock()
|
s.listenersMut.Lock()
|
||||||
seen := make(map[string]struct{})
|
seen := make(map[string]struct{})
|
||||||
for _, addr := range config.Wrap("", to).ListenAddresses() {
|
for _, addr := range config.Wrap("", to, s.evLogger).ListenAddresses() {
|
||||||
if addr == "" {
|
if addr == "" {
|
||||||
// We can get an empty address if there is an empty listener
|
// We can get an empty address if there is an empty listener
|
||||||
// element in the config, indicating no listeners should be
|
// element in the config, indicating no listeners should be
|
||||||
|
|||||||
@ -35,6 +35,7 @@ type globalClient struct {
|
|||||||
queryClient httpClient
|
queryClient httpClient
|
||||||
noAnnounce bool
|
noAnnounce bool
|
||||||
noLookup bool
|
noLookup bool
|
||||||
|
evLogger events.Logger
|
||||||
errorHolder
|
errorHolder
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +71,7 @@ func (e lookupError) CacheFor() time.Duration {
|
|||||||
return e.cacheFor
|
return e.cacheFor
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGlobal(server string, cert tls.Certificate, addrList AddressLister) (FinderService, error) {
|
func NewGlobal(server string, cert tls.Certificate, addrList AddressLister, evLogger events.Logger) (FinderService, error) {
|
||||||
server, opts, err := parseOptions(server)
|
server, opts, err := parseOptions(server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -125,6 +126,7 @@ func NewGlobal(server string, cert tls.Certificate, addrList AddressLister) (Fin
|
|||||||
queryClient: queryClient,
|
queryClient: queryClient,
|
||||||
noAnnounce: opts.noAnnounce,
|
noAnnounce: opts.noAnnounce,
|
||||||
noLookup: opts.noLookup,
|
noLookup: opts.noLookup,
|
||||||
|
evLogger: evLogger,
|
||||||
}
|
}
|
||||||
cl.Service = util.AsService(cl.serve)
|
cl.Service = util.AsService(cl.serve)
|
||||||
if !opts.noAnnounce {
|
if !opts.noAnnounce {
|
||||||
@ -197,8 +199,8 @@ func (c *globalClient) serve(stop chan struct{}) {
|
|||||||
timer := time.NewTimer(0)
|
timer := time.NewTimer(0)
|
||||||
defer timer.Stop()
|
defer timer.Stop()
|
||||||
|
|
||||||
eventSub := events.Default.Subscribe(events.ListenAddressesChanged)
|
eventSub := c.evLogger.Subscribe(events.ListenAddressesChanged)
|
||||||
defer events.Default.Unsubscribe(eventSub)
|
defer eventSub.Unsubscribe()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
"github.com/syncthing/syncthing/lib/tlsutil"
|
"github.com/syncthing/syncthing/lib/tlsutil"
|
||||||
)
|
)
|
||||||
@ -54,15 +55,15 @@ func TestGlobalOverHTTP(t *testing.T) {
|
|||||||
// is only allowed in combination with the "insecure" and "noannounce"
|
// is only allowed in combination with the "insecure" and "noannounce"
|
||||||
// parameters.
|
// parameters.
|
||||||
|
|
||||||
if _, err := NewGlobal("http://192.0.2.42/", tls.Certificate{}, nil); err == nil {
|
if _, err := NewGlobal("http://192.0.2.42/", tls.Certificate{}, nil, events.NoopLogger); err == nil {
|
||||||
t.Fatal("http is not allowed without insecure and noannounce")
|
t.Fatal("http is not allowed without insecure and noannounce")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := NewGlobal("http://192.0.2.42/?insecure", tls.Certificate{}, nil); err == nil {
|
if _, err := NewGlobal("http://192.0.2.42/?insecure", tls.Certificate{}, nil, events.NoopLogger); err == nil {
|
||||||
t.Fatal("http is not allowed without noannounce")
|
t.Fatal("http is not allowed without noannounce")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := NewGlobal("http://192.0.2.42/?noannounce", tls.Certificate{}, nil); err == nil {
|
if _, err := NewGlobal("http://192.0.2.42/?noannounce", tls.Certificate{}, nil, events.NoopLogger); err == nil {
|
||||||
t.Fatal("http is not allowed without insecure")
|
t.Fatal("http is not allowed without insecure")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +194,7 @@ func TestGlobalAnnounce(t *testing.T) {
|
|||||||
go func() { _ = http.Serve(list, mux) }()
|
go func() { _ = http.Serve(list, mux) }()
|
||||||
|
|
||||||
url := "https://" + list.Addr().String() + "?insecure"
|
url := "https://" + list.Addr().String() + "?insecure"
|
||||||
disco, err := NewGlobal(url, cert, new(fakeAddressLister))
|
disco, err := NewGlobal(url, cert, new(fakeAddressLister), events.NoopLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -217,7 +218,7 @@ func TestGlobalAnnounce(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testLookup(url string) ([]string, error) {
|
func testLookup(url string) ([]string, error) {
|
||||||
disco, err := NewGlobal(url, tls.Certificate{}, nil)
|
disco, err := NewGlobal(url, tls.Certificate{}, nil, events.NoopLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@ type localClient struct {
|
|||||||
myID protocol.DeviceID
|
myID protocol.DeviceID
|
||||||
addrList AddressLister
|
addrList AddressLister
|
||||||
name string
|
name string
|
||||||
|
evLogger events.Logger
|
||||||
|
|
||||||
beacon beacon.Interface
|
beacon beacon.Interface
|
||||||
localBcastStart time.Time
|
localBcastStart time.Time
|
||||||
@ -46,13 +47,14 @@ const (
|
|||||||
v13Magic = uint32(0x7D79BC40) // previous version
|
v13Magic = uint32(0x7D79BC40) // previous version
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewLocal(id protocol.DeviceID, addr string, addrList AddressLister) (FinderService, error) {
|
func NewLocal(id protocol.DeviceID, addr string, addrList AddressLister, evLogger events.Logger) (FinderService, error) {
|
||||||
c := &localClient{
|
c := &localClient{
|
||||||
Supervisor: suture.New("local", suture.Spec{
|
Supervisor: suture.New("local", suture.Spec{
|
||||||
PassThroughPanics: true,
|
PassThroughPanics: true,
|
||||||
}),
|
}),
|
||||||
myID: id,
|
myID: id,
|
||||||
addrList: addrList,
|
addrList: addrList,
|
||||||
|
evLogger: evLogger,
|
||||||
localBcastTick: time.NewTicker(BroadcastInterval).C,
|
localBcastTick: time.NewTicker(BroadcastInterval).C,
|
||||||
forcedBcastTick: make(chan time.Time),
|
forcedBcastTick: make(chan time.Time),
|
||||||
localBcastStart: time.Now(),
|
localBcastStart: time.Now(),
|
||||||
@ -272,7 +274,7 @@ func (c *localClient) registerDevice(src net.Addr, device Announce) bool {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if isNewDevice {
|
if isNewDevice {
|
||||||
events.Default.Log(events.DeviceDiscovered, map[string]interface{}{
|
c.evLogger.Log(events.DeviceDiscovered, map[string]interface{}{
|
||||||
"device": device.ID.String(),
|
"device": device.ID.String(),
|
||||||
"addrs": validAddresses,
|
"addrs": validAddresses,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -11,11 +11,12 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLocalInstanceID(t *testing.T) {
|
func TestLocalInstanceID(t *testing.T) {
|
||||||
c, err := NewLocal(protocol.LocalDeviceID, ":0", &fakeAddressLister{})
|
c, err := NewLocal(protocol.LocalDeviceID, ":0", &fakeAddressLister{}, events.NoopLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -38,7 +39,7 @@ func TestLocalInstanceID(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocalInstanceIDShouldTriggerNew(t *testing.T) {
|
func TestLocalInstanceIDShouldTriggerNew(t *testing.T) {
|
||||||
c, err := NewLocal(protocol.LocalDeviceID, ":0", &fakeAddressLister{})
|
c, err := NewLocal(protocol.LocalDeviceID, ":0", &fakeAddressLister{}, events.NoopLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,11 +10,11 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/lib/logger"
|
liblogger "github.com/syncthing/syncthing/lib/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
dl = logger.DefaultLogger.NewFacility("events", "Event generation and logging")
|
dl = liblogger.DefaultLogger.NewFacility("events", "Event generation and logging")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@ -13,7 +13,10 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/thejerf/suture"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/lib/sync"
|
"github.com/syncthing/syncthing/lib/sync"
|
||||||
|
"github.com/syncthing/syncthing/lib/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EventType int
|
type EventType int
|
||||||
@ -51,7 +54,10 @@ const (
|
|||||||
AllEvents = (1 << iota) - 1
|
AllEvents = (1 << iota) - 1
|
||||||
)
|
)
|
||||||
|
|
||||||
var runningTests = false
|
var (
|
||||||
|
runningTests = false
|
||||||
|
errNoop = errors.New("method of a noop object called")
|
||||||
|
)
|
||||||
|
|
||||||
const eventLogTimeout = 15 * time.Millisecond
|
const eventLogTimeout = 15 * time.Millisecond
|
||||||
|
|
||||||
@ -199,13 +205,21 @@ func UnmarshalEventType(s string) EventType {
|
|||||||
|
|
||||||
const BufferSize = 64
|
const BufferSize = 64
|
||||||
|
|
||||||
type Logger struct {
|
type Logger interface {
|
||||||
subs []*Subscription
|
suture.Service
|
||||||
|
Log(t EventType, data interface{})
|
||||||
|
Subscribe(mask EventType) Subscription
|
||||||
|
}
|
||||||
|
|
||||||
|
type logger struct {
|
||||||
|
suture.Service
|
||||||
|
subs []*subscription
|
||||||
nextSubscriptionIDs []int
|
nextSubscriptionIDs []int
|
||||||
nextGlobalID int
|
nextGlobalID int
|
||||||
timeout *time.Timer
|
timeout *time.Timer
|
||||||
events chan Event
|
events chan Event
|
||||||
funcs chan func()
|
funcs chan func()
|
||||||
|
toUnsubscribe chan *subscription
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,19 +233,17 @@ type Event struct {
|
|||||||
Data interface{} `json:"data"`
|
Data interface{} `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Subscription struct {
|
type Subscription interface {
|
||||||
mask EventType
|
C() <-chan Event
|
||||||
events chan Event
|
Poll(timeout time.Duration) (Event, error)
|
||||||
timeout *time.Timer
|
Unsubscribe()
|
||||||
}
|
}
|
||||||
|
|
||||||
var Default = NewLogger()
|
type subscription struct {
|
||||||
|
mask EventType
|
||||||
func init() {
|
events chan Event
|
||||||
// The default logger never stops. To ensure this we nil out the stop
|
toUnsubscribe chan *subscription
|
||||||
// channel so any attempt to stop it will panic.
|
timeout *time.Timer
|
||||||
Default.stop = nil
|
|
||||||
go Default.Serve()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -239,13 +251,14 @@ var (
|
|||||||
ErrClosed = errors.New("closed")
|
ErrClosed = errors.New("closed")
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewLogger() *Logger {
|
func NewLogger() Logger {
|
||||||
l := &Logger{
|
l := &logger{
|
||||||
timeout: time.NewTimer(time.Second),
|
timeout: time.NewTimer(time.Second),
|
||||||
events: make(chan Event, BufferSize),
|
events: make(chan Event, BufferSize),
|
||||||
funcs: make(chan func()),
|
funcs: make(chan func()),
|
||||||
stop: make(chan struct{}),
|
toUnsubscribe: make(chan *subscription),
|
||||||
}
|
}
|
||||||
|
l.Service = util.AsService(l.serve)
|
||||||
// Make sure the timer is in the stopped state and hasn't fired anything
|
// Make sure the timer is in the stopped state and hasn't fired anything
|
||||||
// into the channel.
|
// into the channel.
|
||||||
if !l.timeout.Stop() {
|
if !l.timeout.Stop() {
|
||||||
@ -254,7 +267,7 @@ func NewLogger() *Logger {
|
|||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) Serve() {
|
func (l *logger) serve(stop chan struct{}) {
|
||||||
loop:
|
loop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@ -263,10 +276,13 @@ loop:
|
|||||||
l.sendEvent(e)
|
l.sendEvent(e)
|
||||||
|
|
||||||
case fn := <-l.funcs:
|
case fn := <-l.funcs:
|
||||||
// Subscriptions etc are handled here.
|
// Subscriptions are handled here.
|
||||||
fn()
|
fn()
|
||||||
|
|
||||||
case <-l.stop:
|
case s := <-l.toUnsubscribe:
|
||||||
|
l.unsubscribe(s)
|
||||||
|
|
||||||
|
case <-stop:
|
||||||
break loop
|
break loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,11 +295,7 @@ loop:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) Stop() {
|
func (l *logger) Log(t EventType, data interface{}) {
|
||||||
close(l.stop)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) Log(t EventType, data interface{}) {
|
|
||||||
l.events <- Event{
|
l.events <- Event{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Type: t,
|
Type: t,
|
||||||
@ -292,7 +304,7 @@ func (l *Logger) Log(t EventType, data interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) sendEvent(e Event) {
|
func (l *logger) sendEvent(e Event) {
|
||||||
l.nextGlobalID++
|
l.nextGlobalID++
|
||||||
dl.Debugln("log", l.nextGlobalID, e.Type, e.Data)
|
dl.Debugln("log", l.nextGlobalID, e.Type, e.Data)
|
||||||
|
|
||||||
@ -323,14 +335,15 @@ func (l *Logger) sendEvent(e Event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) Subscribe(mask EventType) *Subscription {
|
func (l *logger) Subscribe(mask EventType) Subscription {
|
||||||
res := make(chan *Subscription)
|
res := make(chan Subscription)
|
||||||
l.funcs <- func() {
|
l.funcs <- func() {
|
||||||
dl.Debugln("subscribe", mask)
|
dl.Debugln("subscribe", mask)
|
||||||
|
|
||||||
s := &Subscription{
|
s := &subscription{
|
||||||
mask: mask,
|
mask: mask,
|
||||||
events: make(chan Event, BufferSize),
|
events: make(chan Event, BufferSize),
|
||||||
|
toUnsubscribe: l.toUnsubscribe,
|
||||||
timeout: time.NewTimer(0),
|
timeout: time.NewTimer(0),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,9 +368,8 @@ func (l *Logger) Subscribe(mask EventType) *Subscription {
|
|||||||
return <-res
|
return <-res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) Unsubscribe(s *Subscription) {
|
func (l *logger) unsubscribe(s *subscription) {
|
||||||
l.funcs <- func() {
|
dl.Debugln("unsubscribe", s.mask)
|
||||||
dl.Debugln("unsubscribe")
|
|
||||||
for i, ss := range l.subs {
|
for i, ss := range l.subs {
|
||||||
if s == ss {
|
if s == ss {
|
||||||
last := len(l.subs) - 1
|
last := len(l.subs) - 1
|
||||||
@ -375,12 +387,11 @@ func (l *Logger) Unsubscribe(s *Subscription) {
|
|||||||
}
|
}
|
||||||
close(s.events)
|
close(s.events)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Poll returns an event from the subscription or an error if the poll times
|
// Poll returns an event from the subscription or an error if the poll times
|
||||||
// out of the event channel is closed. Poll should not be called concurrently
|
// out of the event channel is closed. Poll should not be called concurrently
|
||||||
// from multiple goroutines for a single subscription.
|
// from multiple goroutines for a single subscription.
|
||||||
func (s *Subscription) Poll(timeout time.Duration) (Event, error) {
|
func (s *subscription) Poll(timeout time.Duration) (Event, error) {
|
||||||
dl.Debugln("poll", timeout)
|
dl.Debugln("poll", timeout)
|
||||||
|
|
||||||
s.timeout.Reset(timeout)
|
s.timeout.Reset(timeout)
|
||||||
@ -409,12 +420,16 @@ func (s *Subscription) Poll(timeout time.Duration) (Event, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Subscription) C() <-chan Event {
|
func (s *subscription) C() <-chan Event {
|
||||||
return s.events
|
return s.events
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *subscription) Unsubscribe() {
|
||||||
|
s.toUnsubscribe <- s
|
||||||
|
}
|
||||||
|
|
||||||
type bufferedSubscription struct {
|
type bufferedSubscription struct {
|
||||||
sub *Subscription
|
sub Subscription
|
||||||
buf []Event
|
buf []Event
|
||||||
next int
|
next int
|
||||||
cur int // Current SubscriptionID
|
cur int // Current SubscriptionID
|
||||||
@ -426,7 +441,7 @@ type BufferedSubscription interface {
|
|||||||
Since(id int, into []Event, timeout time.Duration) []Event
|
Since(id int, into []Event, timeout time.Duration) []Event
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBufferedSubscription(s *Subscription, size int) BufferedSubscription {
|
func NewBufferedSubscription(s Subscription, size int) BufferedSubscription {
|
||||||
bs := &bufferedSubscription{
|
bs := &bufferedSubscription{
|
||||||
sub: s,
|
sub: s,
|
||||||
buf: make([]Event, size),
|
buf: make([]Event, size),
|
||||||
@ -489,3 +504,29 @@ func Error(err error) *string {
|
|||||||
str := err.Error()
|
str := err.Error()
|
||||||
return &str
|
return &str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type noopLogger struct{}
|
||||||
|
|
||||||
|
var NoopLogger Logger = &noopLogger{}
|
||||||
|
|
||||||
|
func (*noopLogger) Serve() {}
|
||||||
|
|
||||||
|
func (*noopLogger) Stop() {}
|
||||||
|
|
||||||
|
func (*noopLogger) Log(t EventType, data interface{}) {}
|
||||||
|
|
||||||
|
func (*noopLogger) Subscribe(mask EventType) Subscription {
|
||||||
|
return &noopSubscription{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopSubscription struct{}
|
||||||
|
|
||||||
|
func (*noopSubscription) C() <-chan Event {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*noopSubscription) Poll(timeout time.Duration) (Event, error) {
|
||||||
|
return Event{}, errNoop
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*noopSubscription) Unsubscribe() {}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ func TestSubscriber(t *testing.T) {
|
|||||||
go l.Serve()
|
go l.Serve()
|
||||||
|
|
||||||
s := l.Subscribe(0)
|
s := l.Subscribe(0)
|
||||||
defer l.Unsubscribe(s)
|
defer s.Unsubscribe()
|
||||||
if s == nil {
|
if s == nil {
|
||||||
t.Fatal("Unexpected nil Subscription")
|
t.Fatal("Unexpected nil Subscription")
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ func TestTimeout(t *testing.T) {
|
|||||||
go l.Serve()
|
go l.Serve()
|
||||||
|
|
||||||
s := l.Subscribe(0)
|
s := l.Subscribe(0)
|
||||||
defer l.Unsubscribe(s)
|
defer s.Unsubscribe()
|
||||||
_, err := s.Poll(timeout)
|
_, err := s.Poll(timeout)
|
||||||
if err != ErrTimeout {
|
if err != ErrTimeout {
|
||||||
t.Fatal("Unexpected non-Timeout error:", err)
|
t.Fatal("Unexpected non-Timeout error:", err)
|
||||||
@ -59,7 +59,7 @@ func TestEventBeforeSubscribe(t *testing.T) {
|
|||||||
|
|
||||||
l.Log(DeviceConnected, "foo")
|
l.Log(DeviceConnected, "foo")
|
||||||
s := l.Subscribe(0)
|
s := l.Subscribe(0)
|
||||||
defer l.Unsubscribe(s)
|
defer s.Unsubscribe()
|
||||||
|
|
||||||
_, err := s.Poll(timeout)
|
_, err := s.Poll(timeout)
|
||||||
if err != ErrTimeout {
|
if err != ErrTimeout {
|
||||||
@ -73,7 +73,7 @@ func TestEventAfterSubscribe(t *testing.T) {
|
|||||||
go l.Serve()
|
go l.Serve()
|
||||||
|
|
||||||
s := l.Subscribe(AllEvents)
|
s := l.Subscribe(AllEvents)
|
||||||
defer l.Unsubscribe(s)
|
defer s.Unsubscribe()
|
||||||
l.Log(DeviceConnected, "foo")
|
l.Log(DeviceConnected, "foo")
|
||||||
|
|
||||||
ev, err := s.Poll(timeout)
|
ev, err := s.Poll(timeout)
|
||||||
@ -100,7 +100,7 @@ func TestEventAfterSubscribeIgnoreMask(t *testing.T) {
|
|||||||
go l.Serve()
|
go l.Serve()
|
||||||
|
|
||||||
s := l.Subscribe(DeviceDisconnected)
|
s := l.Subscribe(DeviceDisconnected)
|
||||||
defer l.Unsubscribe(s)
|
defer s.Unsubscribe()
|
||||||
l.Log(DeviceConnected, "foo")
|
l.Log(DeviceConnected, "foo")
|
||||||
|
|
||||||
_, err := s.Poll(timeout)
|
_, err := s.Poll(timeout)
|
||||||
@ -115,7 +115,7 @@ func TestBufferOverflow(t *testing.T) {
|
|||||||
go l.Serve()
|
go l.Serve()
|
||||||
|
|
||||||
s := l.Subscribe(AllEvents)
|
s := l.Subscribe(AllEvents)
|
||||||
defer l.Unsubscribe(s)
|
defer s.Unsubscribe()
|
||||||
|
|
||||||
// The first BufferSize events will be logged pretty much
|
// The first BufferSize events will be logged pretty much
|
||||||
// instantaneously. The next BufferSize events will each block for up to
|
// instantaneously. The next BufferSize events will each block for up to
|
||||||
@ -147,7 +147,7 @@ func TestUnsubscribe(t *testing.T) {
|
|||||||
t.Fatal("Unexpected error:", err)
|
t.Fatal("Unexpected error:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
l.Unsubscribe(s)
|
s.Unsubscribe()
|
||||||
l.Log(DeviceConnected, "foo")
|
l.Log(DeviceConnected, "foo")
|
||||||
|
|
||||||
_, err = s.Poll(timeout)
|
_, err = s.Poll(timeout)
|
||||||
@ -162,7 +162,7 @@ func TestGlobalIDs(t *testing.T) {
|
|||||||
go l.Serve()
|
go l.Serve()
|
||||||
|
|
||||||
s := l.Subscribe(AllEvents)
|
s := l.Subscribe(AllEvents)
|
||||||
defer l.Unsubscribe(s)
|
defer s.Unsubscribe()
|
||||||
l.Log(DeviceConnected, "foo")
|
l.Log(DeviceConnected, "foo")
|
||||||
l.Subscribe(AllEvents)
|
l.Subscribe(AllEvents)
|
||||||
l.Log(DeviceConnected, "bar")
|
l.Log(DeviceConnected, "bar")
|
||||||
@ -194,7 +194,7 @@ func TestSubscriptionIDs(t *testing.T) {
|
|||||||
go l.Serve()
|
go l.Serve()
|
||||||
|
|
||||||
s := l.Subscribe(DeviceConnected)
|
s := l.Subscribe(DeviceConnected)
|
||||||
defer l.Unsubscribe(s)
|
defer s.Unsubscribe()
|
||||||
|
|
||||||
l.Log(DeviceDisconnected, "a")
|
l.Log(DeviceDisconnected, "a")
|
||||||
l.Log(DeviceConnected, "b")
|
l.Log(DeviceConnected, "b")
|
||||||
@ -236,7 +236,7 @@ func TestBufferedSub(t *testing.T) {
|
|||||||
go l.Serve()
|
go l.Serve()
|
||||||
|
|
||||||
s := l.Subscribe(AllEvents)
|
s := l.Subscribe(AllEvents)
|
||||||
defer l.Unsubscribe(s)
|
defer s.Unsubscribe()
|
||||||
bs := NewBufferedSubscription(s, 10*BufferSize)
|
bs := NewBufferedSubscription(s, 10*BufferSize)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -267,7 +267,7 @@ func BenchmarkBufferedSub(b *testing.B) {
|
|||||||
go l.Serve()
|
go l.Serve()
|
||||||
|
|
||||||
s := l.Subscribe(AllEvents)
|
s := l.Subscribe(AllEvents)
|
||||||
defer l.Unsubscribe(s)
|
defer s.Unsubscribe()
|
||||||
bufferSize := BufferSize
|
bufferSize := BufferSize
|
||||||
bs := NewBufferedSubscription(s, bufferSize)
|
bs := NewBufferedSubscription(s, bufferSize)
|
||||||
|
|
||||||
@ -323,7 +323,7 @@ func TestSinceUsesSubscriptionId(t *testing.T) {
|
|||||||
go l.Serve()
|
go l.Serve()
|
||||||
|
|
||||||
s := l.Subscribe(DeviceConnected)
|
s := l.Subscribe(DeviceConnected)
|
||||||
defer l.Unsubscribe(s)
|
defer s.Unsubscribe()
|
||||||
bs := NewBufferedSubscription(s, 10*BufferSize)
|
bs := NewBufferedSubscription(s, 10*BufferSize)
|
||||||
|
|
||||||
l.Log(DeviceConnected, "a") // SubscriptionID = 1
|
l.Log(DeviceConnected, "a") // SubscriptionID = 1
|
||||||
@ -390,7 +390,7 @@ func TestUnsubscribeContention(t *testing.T) {
|
|||||||
defer listenerWg.Done()
|
defer listenerWg.Done()
|
||||||
|
|
||||||
s := l.Subscribe(AllEvents)
|
s := l.Subscribe(AllEvents)
|
||||||
defer l.Unsubscribe(s)
|
defer s.Unsubscribe()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@ -449,7 +449,7 @@ func BenchmarkLogEvent(b *testing.B) {
|
|||||||
go l.Serve()
|
go l.Serve()
|
||||||
|
|
||||||
s := l.Subscribe(AllEvents)
|
s := l.Subscribe(AllEvents)
|
||||||
defer l.Unsubscribe(s)
|
defer s.Unsubscribe()
|
||||||
NewBufferedSubscription(s, 1) // runs in the background
|
NewBufferedSubscription(s, 1) // runs in the background
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
|
|||||||
@ -77,11 +77,11 @@ type puller interface {
|
|||||||
pull() bool // true when successfull and should not be retried
|
pull() bool // true when successfull and should not be retried
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg config.FolderConfiguration) folder {
|
func newFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg config.FolderConfiguration, evLogger events.Logger) folder {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
return folder{
|
return folder{
|
||||||
stateTracker: newStateTracker(cfg.ID),
|
stateTracker: newStateTracker(cfg.ID, evLogger),
|
||||||
FolderConfiguration: cfg,
|
FolderConfiguration: cfg,
|
||||||
FolderStatisticsReference: stats.NewFolderStatisticsReference(model.db, cfg.ID),
|
FolderStatisticsReference: stats.NewFolderStatisticsReference(model.db, cfg.ID),
|
||||||
|
|
||||||
@ -630,7 +630,7 @@ func (f *folder) monitorWatch(ctx context.Context) {
|
|||||||
failTimer.Reset(time.Minute)
|
failTimer.Reset(time.Minute)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
watchaggregator.Aggregate(eventChan, f.watchChan, f.FolderConfiguration, f.model.cfg, aggrCtx)
|
watchaggregator.Aggregate(eventChan, f.watchChan, f.FolderConfiguration, f.model.cfg, f.evLogger, aggrCtx)
|
||||||
l.Debugln("Started filesystem watcher for folder", f.Description())
|
l.Debugln("Started filesystem watcher for folder", f.Description())
|
||||||
case err = <-errChan:
|
case err = <-errChan:
|
||||||
f.setWatchError(err)
|
f.setWatchError(err)
|
||||||
@ -669,7 +669,7 @@ func (f *folder) setWatchError(err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
data["to"] = err.Error()
|
data["to"] = err.Error()
|
||||||
}
|
}
|
||||||
events.Default.Log(events.FolderWatchStateChanged, data)
|
f.evLogger.Log(events.FolderWatchStateChanged, data)
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
@ -800,7 +800,7 @@ func (f *folder) updateLocals(fs []protocol.FileInfo) {
|
|||||||
filenames[i] = file.Name
|
filenames[i] = file.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
events.Default.Log(events.LocalIndexUpdated, map[string]interface{}{
|
f.evLogger.Log(events.LocalIndexUpdated, map[string]interface{}{
|
||||||
"folder": f.ID,
|
"folder": f.ID,
|
||||||
"items": len(fs),
|
"items": len(fs),
|
||||||
"filenames": filenames,
|
"filenames": filenames,
|
||||||
@ -839,7 +839,7 @@ func (f *folder) emitDiskChangeEvents(fs []protocol.FileInfo, typeOfEvent events
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Two different events can be fired here based on what EventType is passed into function
|
// Two different events can be fired here based on what EventType is passed into function
|
||||||
events.Default.Log(typeOfEvent, map[string]string{
|
f.evLogger.Log(typeOfEvent, map[string]string{
|
||||||
"folder": f.ID,
|
"folder": f.ID,
|
||||||
"folderID": f.ID, // incorrect, deprecated, kept for historical compliance
|
"folderID": f.ID, // incorrect, deprecated, kept for historical compliance
|
||||||
"label": f.Label,
|
"label": f.Label,
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/syncthing/syncthing/lib/config"
|
"github.com/syncthing/syncthing/lib/config"
|
||||||
"github.com/syncthing/syncthing/lib/db"
|
"github.com/syncthing/syncthing/lib/db"
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/fs"
|
"github.com/syncthing/syncthing/lib/fs"
|
||||||
"github.com/syncthing/syncthing/lib/ignore"
|
"github.com/syncthing/syncthing/lib/ignore"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
@ -56,8 +57,8 @@ type receiveOnlyFolder struct {
|
|||||||
*sendReceiveFolder
|
*sendReceiveFolder
|
||||||
}
|
}
|
||||||
|
|
||||||
func newReceiveOnlyFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg config.FolderConfiguration, ver versioner.Versioner, fs fs.Filesystem) service {
|
func newReceiveOnlyFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg config.FolderConfiguration, ver versioner.Versioner, fs fs.Filesystem, evLogger events.Logger) service {
|
||||||
sr := newSendReceiveFolder(model, fset, ignores, cfg, ver, fs).(*sendReceiveFolder)
|
sr := newSendReceiveFolder(model, fset, ignores, cfg, ver, fs, evLogger).(*sendReceiveFolder)
|
||||||
sr.localFlags = protocol.FlagLocalReceiveOnly // gets propagated to the scanner, and set on locally changed files
|
sr.localFlags = protocol.FlagLocalReceiveOnly // gets propagated to the scanner, and set on locally changed files
|
||||||
return &receiveOnlyFolder{sr}
|
return &receiveOnlyFolder{sr}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -321,6 +321,7 @@ func setupROFolder() (*model, *sendOnlyFolder) {
|
|||||||
|
|
||||||
f := &sendOnlyFolder{
|
f := &sendOnlyFolder{
|
||||||
folder: folder{
|
folder: folder{
|
||||||
|
stateTracker: newStateTracker(fcfg.ID, m.evLogger),
|
||||||
fset: m.folderFiles[fcfg.ID],
|
fset: m.folderFiles[fcfg.ID],
|
||||||
FolderConfiguration: fcfg,
|
FolderConfiguration: fcfg,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -9,6 +9,7 @@ package model
|
|||||||
import (
|
import (
|
||||||
"github.com/syncthing/syncthing/lib/config"
|
"github.com/syncthing/syncthing/lib/config"
|
||||||
"github.com/syncthing/syncthing/lib/db"
|
"github.com/syncthing/syncthing/lib/db"
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/fs"
|
"github.com/syncthing/syncthing/lib/fs"
|
||||||
"github.com/syncthing/syncthing/lib/ignore"
|
"github.com/syncthing/syncthing/lib/ignore"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
@ -24,9 +25,9 @@ type sendOnlyFolder struct {
|
|||||||
folder
|
folder
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSendOnlyFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg config.FolderConfiguration, _ versioner.Versioner, _ fs.Filesystem) service {
|
func newSendOnlyFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg config.FolderConfiguration, _ versioner.Versioner, _ fs.Filesystem, evLogger events.Logger) service {
|
||||||
f := &sendOnlyFolder{
|
f := &sendOnlyFolder{
|
||||||
folder: newFolder(model, fset, ignores, cfg),
|
folder: newFolder(model, fset, ignores, cfg, evLogger),
|
||||||
}
|
}
|
||||||
f.folder.puller = f
|
f.folder.puller = f
|
||||||
f.folder.Service = util.AsService(f.serve)
|
f.folder.Service = util.AsService(f.serve)
|
||||||
|
|||||||
@ -108,9 +108,9 @@ type sendReceiveFolder struct {
|
|||||||
pullErrorsMut sync.Mutex
|
pullErrorsMut sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSendReceiveFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg config.FolderConfiguration, ver versioner.Versioner, fs fs.Filesystem) service {
|
func newSendReceiveFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg config.FolderConfiguration, ver versioner.Versioner, fs fs.Filesystem, evLogger events.Logger) service {
|
||||||
f := &sendReceiveFolder{
|
f := &sendReceiveFolder{
|
||||||
folder: newFolder(model, fset, ignores, cfg),
|
folder: newFolder(model, fset, ignores, cfg, evLogger),
|
||||||
fs: fs,
|
fs: fs,
|
||||||
versioner: ver,
|
versioner: ver,
|
||||||
queue: newJobQueue(),
|
queue: newJobQueue(),
|
||||||
@ -211,7 +211,7 @@ func (f *sendReceiveFolder) pull() bool {
|
|||||||
// errors preventing us. Flag this with a warning and
|
// errors preventing us. Flag this with a warning and
|
||||||
// wait a bit longer before retrying.
|
// wait a bit longer before retrying.
|
||||||
if errors := f.Errors(); len(errors) > 0 {
|
if errors := f.Errors(); len(errors) > 0 {
|
||||||
events.Default.Log(events.FolderErrors, map[string]interface{}{
|
f.evLogger.Log(events.FolderErrors, map[string]interface{}{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"errors": errors,
|
"errors": errors,
|
||||||
})
|
})
|
||||||
@ -544,7 +544,7 @@ func (f *sendReceiveFolder) handleDir(file protocol.FileInfo, dbUpdateChan chan<
|
|||||||
|
|
||||||
f.resetPullError(file.Name)
|
f.resetPullError(file.Name)
|
||||||
|
|
||||||
events.Default.Log(events.ItemStarted, map[string]string{
|
f.evLogger.Log(events.ItemStarted, map[string]string{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": file.Name,
|
"item": file.Name,
|
||||||
"type": "dir",
|
"type": "dir",
|
||||||
@ -552,7 +552,7 @@ func (f *sendReceiveFolder) handleDir(file protocol.FileInfo, dbUpdateChan chan<
|
|||||||
})
|
})
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
events.Default.Log(events.ItemFinished, map[string]interface{}{
|
f.evLogger.Log(events.ItemFinished, map[string]interface{}{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": file.Name,
|
"item": file.Name,
|
||||||
"error": events.Error(err),
|
"error": events.Error(err),
|
||||||
@ -700,7 +700,7 @@ func (f *sendReceiveFolder) handleSymlink(file protocol.FileInfo, dbUpdateChan c
|
|||||||
|
|
||||||
f.resetPullError(file.Name)
|
f.resetPullError(file.Name)
|
||||||
|
|
||||||
events.Default.Log(events.ItemStarted, map[string]string{
|
f.evLogger.Log(events.ItemStarted, map[string]string{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": file.Name,
|
"item": file.Name,
|
||||||
"type": "symlink",
|
"type": "symlink",
|
||||||
@ -708,7 +708,7 @@ func (f *sendReceiveFolder) handleSymlink(file protocol.FileInfo, dbUpdateChan c
|
|||||||
})
|
})
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
events.Default.Log(events.ItemFinished, map[string]interface{}{
|
f.evLogger.Log(events.ItemFinished, map[string]interface{}{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": file.Name,
|
"item": file.Name,
|
||||||
"error": events.Error(err),
|
"error": events.Error(err),
|
||||||
@ -782,7 +782,7 @@ func (f *sendReceiveFolder) deleteDir(file protocol.FileInfo, dbUpdateChan chan<
|
|||||||
// care not declare another err.
|
// care not declare another err.
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
events.Default.Log(events.ItemStarted, map[string]string{
|
f.evLogger.Log(events.ItemStarted, map[string]string{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": file.Name,
|
"item": file.Name,
|
||||||
"type": "dir",
|
"type": "dir",
|
||||||
@ -790,7 +790,7 @@ func (f *sendReceiveFolder) deleteDir(file protocol.FileInfo, dbUpdateChan chan<
|
|||||||
})
|
})
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
events.Default.Log(events.ItemFinished, map[string]interface{}{
|
f.evLogger.Log(events.ItemFinished, map[string]interface{}{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": file.Name,
|
"item": file.Name,
|
||||||
"error": events.Error(err),
|
"error": events.Error(err),
|
||||||
@ -822,7 +822,7 @@ func (f *sendReceiveFolder) deleteFileWithCurrent(file, cur protocol.FileInfo, h
|
|||||||
|
|
||||||
f.resetPullError(file.Name)
|
f.resetPullError(file.Name)
|
||||||
|
|
||||||
events.Default.Log(events.ItemStarted, map[string]string{
|
f.evLogger.Log(events.ItemStarted, map[string]string{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": file.Name,
|
"item": file.Name,
|
||||||
"type": "file",
|
"type": "file",
|
||||||
@ -833,7 +833,7 @@ func (f *sendReceiveFolder) deleteFileWithCurrent(file, cur protocol.FileInfo, h
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
f.newPullError(file.Name, errors.Wrap(err, "delete file"))
|
f.newPullError(file.Name, errors.Wrap(err, "delete file"))
|
||||||
}
|
}
|
||||||
events.Default.Log(events.ItemFinished, map[string]interface{}{
|
f.evLogger.Log(events.ItemFinished, map[string]interface{}{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": file.Name,
|
"item": file.Name,
|
||||||
"error": events.Error(err),
|
"error": events.Error(err),
|
||||||
@ -897,13 +897,13 @@ func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, db
|
|||||||
// care not declare another err.
|
// care not declare another err.
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
events.Default.Log(events.ItemStarted, map[string]string{
|
f.evLogger.Log(events.ItemStarted, map[string]string{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": source.Name,
|
"item": source.Name,
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"action": "delete",
|
"action": "delete",
|
||||||
})
|
})
|
||||||
events.Default.Log(events.ItemStarted, map[string]string{
|
f.evLogger.Log(events.ItemStarted, map[string]string{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": target.Name,
|
"item": target.Name,
|
||||||
"type": "file",
|
"type": "file",
|
||||||
@ -911,14 +911,14 @@ func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, db
|
|||||||
})
|
})
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
events.Default.Log(events.ItemFinished, map[string]interface{}{
|
f.evLogger.Log(events.ItemFinished, map[string]interface{}{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": source.Name,
|
"item": source.Name,
|
||||||
"error": events.Error(err),
|
"error": events.Error(err),
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"action": "delete",
|
"action": "delete",
|
||||||
})
|
})
|
||||||
events.Default.Log(events.ItemFinished, map[string]interface{}{
|
f.evLogger.Log(events.ItemFinished, map[string]interface{}{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": target.Name,
|
"item": target.Name,
|
||||||
"error": events.Error(err),
|
"error": events.Error(err),
|
||||||
@ -1095,7 +1095,7 @@ func (f *sendReceiveFolder) handleFile(file protocol.FileInfo, copyChan chan<- c
|
|||||||
// Shuffle the blocks
|
// Shuffle the blocks
|
||||||
rand.Shuffle(blocks)
|
rand.Shuffle(blocks)
|
||||||
|
|
||||||
events.Default.Log(events.ItemStarted, map[string]string{
|
f.evLogger.Log(events.ItemStarted, map[string]string{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": file.Name,
|
"item": file.Name,
|
||||||
"type": "file",
|
"type": "file",
|
||||||
@ -1178,7 +1178,7 @@ func (f *sendReceiveFolder) shortcutFile(file, curFile protocol.FileInfo, dbUpda
|
|||||||
|
|
||||||
f.resetPullError(file.Name)
|
f.resetPullError(file.Name)
|
||||||
|
|
||||||
events.Default.Log(events.ItemStarted, map[string]string{
|
f.evLogger.Log(events.ItemStarted, map[string]string{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": file.Name,
|
"item": file.Name,
|
||||||
"type": "file",
|
"type": "file",
|
||||||
@ -1186,7 +1186,7 @@ func (f *sendReceiveFolder) shortcutFile(file, curFile protocol.FileInfo, dbUpda
|
|||||||
})
|
})
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
defer events.Default.Log(events.ItemFinished, map[string]interface{}{
|
defer f.evLogger.Log(events.ItemFinished, map[string]interface{}{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": file.Name,
|
"item": file.Name,
|
||||||
"error": events.Error(err),
|
"error": events.Error(err),
|
||||||
@ -1575,7 +1575,7 @@ func (f *sendReceiveFolder) finisherRoutine(in <-chan *sharedPullerState, dbUpda
|
|||||||
|
|
||||||
f.model.progressEmitter.Deregister(state)
|
f.model.progressEmitter.Deregister(state)
|
||||||
|
|
||||||
events.Default.Log(events.ItemFinished, map[string]interface{}{
|
f.evLogger.Log(events.ItemFinished, map[string]interface{}{
|
||||||
"folder": f.folderID,
|
"folder": f.folderID,
|
||||||
"item": state.file.Name,
|
"item": state.file.Name,
|
||||||
"error": events.Error(err),
|
"error": events.Error(err),
|
||||||
|
|||||||
@ -96,7 +96,7 @@ func setupSendReceiveFolder(files ...protocol.FileInfo) (*model, *sendReceiveFol
|
|||||||
|
|
||||||
f := &sendReceiveFolder{
|
f := &sendReceiveFolder{
|
||||||
folder: folder{
|
folder: folder{
|
||||||
stateTracker: newStateTracker("default"),
|
stateTracker: newStateTracker("default", model.evLogger),
|
||||||
model: model,
|
model: model,
|
||||||
fset: model.folderFiles[fcfg.ID],
|
fset: model.folderFiles[fcfg.ID],
|
||||||
initialScanFinished: make(chan struct{}),
|
initialScanFinished: make(chan struct{}),
|
||||||
@ -121,6 +121,12 @@ func setupSendReceiveFolder(files ...protocol.FileInfo) (*model, *sendReceiveFol
|
|||||||
return model, f
|
return model, f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cleanupSRFolder(f *sendReceiveFolder, m *model) {
|
||||||
|
m.evLogger.Stop()
|
||||||
|
os.Remove(m.cfg.ConfigPath())
|
||||||
|
os.Remove(f.Filesystem().URI())
|
||||||
|
}
|
||||||
|
|
||||||
// Layout of the files: (indexes from the above array)
|
// Layout of the files: (indexes from the above array)
|
||||||
// 12345678 - Required file
|
// 12345678 - Required file
|
||||||
// 02005008 - Existing file (currently in the index)
|
// 02005008 - Existing file (currently in the index)
|
||||||
@ -137,10 +143,7 @@ func TestHandleFile(t *testing.T) {
|
|||||||
requiredFile.Blocks = blocks[1:]
|
requiredFile.Blocks = blocks[1:]
|
||||||
|
|
||||||
m, f := setupSendReceiveFolder(existingFile)
|
m, f := setupSendReceiveFolder(existingFile)
|
||||||
defer func() {
|
defer cleanupSRFolder(f, m)
|
||||||
os.Remove(m.cfg.ConfigPath())
|
|
||||||
os.Remove(f.Filesystem().URI())
|
|
||||||
}()
|
|
||||||
|
|
||||||
copyChan := make(chan copyBlocksState, 1)
|
copyChan := make(chan copyBlocksState, 1)
|
||||||
dbUpdateChan := make(chan dbUpdateJob, 1)
|
dbUpdateChan := make(chan dbUpdateJob, 1)
|
||||||
@ -183,10 +186,7 @@ func TestHandleFileWithTemp(t *testing.T) {
|
|||||||
requiredFile.Blocks = blocks[1:]
|
requiredFile.Blocks = blocks[1:]
|
||||||
|
|
||||||
m, f := setupSendReceiveFolder(existingFile)
|
m, f := setupSendReceiveFolder(existingFile)
|
||||||
defer func() {
|
defer cleanupSRFolder(f, m)
|
||||||
os.Remove(m.cfg.ConfigPath())
|
|
||||||
os.Remove(f.Filesystem().URI())
|
|
||||||
}()
|
|
||||||
|
|
||||||
if _, err := prepareTmpFile(f.Filesystem()); err != nil {
|
if _, err := prepareTmpFile(f.Filesystem()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -236,10 +236,7 @@ func TestCopierFinder(t *testing.T) {
|
|||||||
requiredFile.Name = "file2"
|
requiredFile.Name = "file2"
|
||||||
|
|
||||||
m, f := setupSendReceiveFolder(existingFile)
|
m, f := setupSendReceiveFolder(existingFile)
|
||||||
defer func() {
|
defer cleanupSRFolder(f, m)
|
||||||
os.Remove(m.cfg.ConfigPath())
|
|
||||||
os.Remove(f.Filesystem().URI())
|
|
||||||
}()
|
|
||||||
|
|
||||||
if _, err := prepareTmpFile(f.Filesystem()); err != nil {
|
if _, err := prepareTmpFile(f.Filesystem()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -302,11 +299,8 @@ func TestCopierFinder(t *testing.T) {
|
|||||||
func TestWeakHash(t *testing.T) {
|
func TestWeakHash(t *testing.T) {
|
||||||
// Setup the model/pull environment
|
// Setup the model/pull environment
|
||||||
model, fo := setupSendReceiveFolder()
|
model, fo := setupSendReceiveFolder()
|
||||||
|
defer cleanupSRFolder(fo, model)
|
||||||
ffs := fo.Filesystem()
|
ffs := fo.Filesystem()
|
||||||
defer func() {
|
|
||||||
os.Remove(model.cfg.ConfigPath())
|
|
||||||
os.Remove(ffs.URI())
|
|
||||||
}()
|
|
||||||
|
|
||||||
tempFile := fs.TempName("weakhash")
|
tempFile := fs.TempName("weakhash")
|
||||||
var shift int64 = 10
|
var shift int64 = 10
|
||||||
@ -432,10 +426,7 @@ func TestCopierCleanup(t *testing.T) {
|
|||||||
// Create a file
|
// Create a file
|
||||||
file := setupFile("test", []int{0})
|
file := setupFile("test", []int{0})
|
||||||
m, f := setupSendReceiveFolder(file)
|
m, f := setupSendReceiveFolder(file)
|
||||||
defer func() {
|
defer cleanupSRFolder(f, m)
|
||||||
os.Remove(m.cfg.ConfigPath())
|
|
||||||
os.Remove(f.Filesystem().URI())
|
|
||||||
}()
|
|
||||||
|
|
||||||
file.Blocks = []protocol.BlockInfo{blocks[1]}
|
file.Blocks = []protocol.BlockInfo{blocks[1]}
|
||||||
file.Version = file.Version.Update(myID.Short())
|
file.Version = file.Version.Update(myID.Short())
|
||||||
@ -468,13 +459,10 @@ func TestDeregisterOnFailInCopy(t *testing.T) {
|
|||||||
file := setupFile("filex", []int{0, 2, 0, 0, 5, 0, 0, 8})
|
file := setupFile("filex", []int{0, 2, 0, 0, 5, 0, 0, 8})
|
||||||
|
|
||||||
m, f := setupSendReceiveFolder()
|
m, f := setupSendReceiveFolder()
|
||||||
defer func() {
|
defer cleanupSRFolder(f, m)
|
||||||
os.Remove(m.cfg.ConfigPath())
|
|
||||||
os.Remove(f.Filesystem().URI())
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Set up our evet subscription early
|
// Set up our evet subscription early
|
||||||
s := events.Default.Subscribe(events.ItemFinished)
|
s := m.evLogger.Subscribe(events.ItemFinished)
|
||||||
|
|
||||||
// queue.Done should be called by the finisher routine
|
// queue.Done should be called by the finisher routine
|
||||||
f.queue.Push("filex", 0, time.Time{})
|
f.queue.Push("filex", 0, time.Time{})
|
||||||
@ -558,13 +546,10 @@ func TestDeregisterOnFailInPull(t *testing.T) {
|
|||||||
file := setupFile("filex", []int{0, 2, 0, 0, 5, 0, 0, 8})
|
file := setupFile("filex", []int{0, 2, 0, 0, 5, 0, 0, 8})
|
||||||
|
|
||||||
m, f := setupSendReceiveFolder()
|
m, f := setupSendReceiveFolder()
|
||||||
defer func() {
|
defer cleanupSRFolder(f, m)
|
||||||
os.Remove(m.cfg.ConfigPath())
|
|
||||||
os.Remove(f.Filesystem().URI())
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Set up our evet subscription early
|
// Set up our evet subscription early
|
||||||
s := events.Default.Subscribe(events.ItemFinished)
|
s := m.evLogger.Subscribe(events.ItemFinished)
|
||||||
|
|
||||||
// queue.Done should be called by the finisher routine
|
// queue.Done should be called by the finisher routine
|
||||||
f.queue.Push("filex", 0, time.Time{})
|
f.queue.Push("filex", 0, time.Time{})
|
||||||
@ -636,12 +621,9 @@ func TestDeregisterOnFailInPull(t *testing.T) {
|
|||||||
|
|
||||||
func TestIssue3164(t *testing.T) {
|
func TestIssue3164(t *testing.T) {
|
||||||
m, f := setupSendReceiveFolder()
|
m, f := setupSendReceiveFolder()
|
||||||
|
defer cleanupSRFolder(f, m)
|
||||||
ffs := f.Filesystem()
|
ffs := f.Filesystem()
|
||||||
tmpDir := ffs.URI()
|
tmpDir := ffs.URI()
|
||||||
defer func() {
|
|
||||||
os.Remove(m.cfg.ConfigPath())
|
|
||||||
os.Remove(tmpDir)
|
|
||||||
}()
|
|
||||||
|
|
||||||
ignDir := filepath.Join("issue3164", "oktodelete")
|
ignDir := filepath.Join("issue3164", "oktodelete")
|
||||||
subDir := filepath.Join(ignDir, "foobar")
|
subDir := filepath.Join(ignDir, "foobar")
|
||||||
@ -728,11 +710,8 @@ func TestDiffEmpty(t *testing.T) {
|
|||||||
// in the db.
|
// in the db.
|
||||||
func TestDeleteIgnorePerms(t *testing.T) {
|
func TestDeleteIgnorePerms(t *testing.T) {
|
||||||
m, f := setupSendReceiveFolder()
|
m, f := setupSendReceiveFolder()
|
||||||
|
defer cleanupSRFolder(f, m)
|
||||||
ffs := f.Filesystem()
|
ffs := f.Filesystem()
|
||||||
defer func() {
|
|
||||||
os.Remove(m.cfg.ConfigPath())
|
|
||||||
os.Remove(ffs.URI())
|
|
||||||
}()
|
|
||||||
f.IgnorePerms = true
|
f.IgnorePerms = true
|
||||||
|
|
||||||
name := "deleteIgnorePerms"
|
name := "deleteIgnorePerms"
|
||||||
@ -778,7 +757,7 @@ func TestCopyOwner(t *testing.T) {
|
|||||||
// filesystem.
|
// filesystem.
|
||||||
|
|
||||||
m, f := setupSendReceiveFolder()
|
m, f := setupSendReceiveFolder()
|
||||||
defer os.Remove(m.cfg.ConfigPath())
|
defer cleanupSRFolder(f, m)
|
||||||
f.folder.FolderConfiguration = config.NewFolderConfiguration(m.id, f.ID, f.Label, fs.FilesystemTypeFake, "/TestCopyOwner")
|
f.folder.FolderConfiguration = config.NewFolderConfiguration(m.id, f.ID, f.Label, fs.FilesystemTypeFake, "/TestCopyOwner")
|
||||||
f.folder.FolderConfiguration.CopyOwnershipFromParent = true
|
f.folder.FolderConfiguration.CopyOwnershipFromParent = true
|
||||||
|
|
||||||
@ -867,11 +846,8 @@ func TestCopyOwner(t *testing.T) {
|
|||||||
// is replaced with a directory and versions are conflicting
|
// is replaced with a directory and versions are conflicting
|
||||||
func TestSRConflictReplaceFileByDir(t *testing.T) {
|
func TestSRConflictReplaceFileByDir(t *testing.T) {
|
||||||
m, f := setupSendReceiveFolder()
|
m, f := setupSendReceiveFolder()
|
||||||
|
defer cleanupSRFolder(f, m)
|
||||||
ffs := f.Filesystem()
|
ffs := f.Filesystem()
|
||||||
defer func() {
|
|
||||||
os.Remove(m.cfg.ConfigPath())
|
|
||||||
os.Remove(ffs.URI())
|
|
||||||
}()
|
|
||||||
|
|
||||||
name := "foo"
|
name := "foo"
|
||||||
|
|
||||||
@ -902,11 +878,8 @@ func TestSRConflictReplaceFileByDir(t *testing.T) {
|
|||||||
// is replaced with a link and versions are conflicting
|
// is replaced with a link and versions are conflicting
|
||||||
func TestSRConflictReplaceFileByLink(t *testing.T) {
|
func TestSRConflictReplaceFileByLink(t *testing.T) {
|
||||||
m, f := setupSendReceiveFolder()
|
m, f := setupSendReceiveFolder()
|
||||||
|
defer cleanupSRFolder(f, m)
|
||||||
ffs := f.Filesystem()
|
ffs := f.Filesystem()
|
||||||
defer func() {
|
|
||||||
os.Remove(m.cfg.ConfigPath())
|
|
||||||
os.Remove(ffs.URI())
|
|
||||||
}()
|
|
||||||
|
|
||||||
name := "foo"
|
name := "foo"
|
||||||
|
|
||||||
|
|||||||
@ -36,6 +36,7 @@ type folderSummaryService struct {
|
|||||||
cfg config.Wrapper
|
cfg config.Wrapper
|
||||||
model Model
|
model Model
|
||||||
id protocol.DeviceID
|
id protocol.DeviceID
|
||||||
|
evLogger events.Logger
|
||||||
immediate chan string
|
immediate chan string
|
||||||
|
|
||||||
// For keeping track of folders to recalculate for
|
// For keeping track of folders to recalculate for
|
||||||
@ -47,7 +48,7 @@ type folderSummaryService struct {
|
|||||||
lastEventReqMut sync.Mutex
|
lastEventReqMut sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFolderSummaryService(cfg config.Wrapper, m Model, id protocol.DeviceID) FolderSummaryService {
|
func NewFolderSummaryService(cfg config.Wrapper, m Model, id protocol.DeviceID, evLogger events.Logger) FolderSummaryService {
|
||||||
service := &folderSummaryService{
|
service := &folderSummaryService{
|
||||||
Supervisor: suture.New("folderSummaryService", suture.Spec{
|
Supervisor: suture.New("folderSummaryService", suture.Spec{
|
||||||
PassThroughPanics: true,
|
PassThroughPanics: true,
|
||||||
@ -55,6 +56,7 @@ func NewFolderSummaryService(cfg config.Wrapper, m Model, id protocol.DeviceID)
|
|||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
model: m,
|
model: m,
|
||||||
id: id,
|
id: id,
|
||||||
|
evLogger: evLogger,
|
||||||
immediate: make(chan string),
|
immediate: make(chan string),
|
||||||
folders: make(map[string]struct{}),
|
folders: make(map[string]struct{}),
|
||||||
foldersMut: sync.NewMutex(),
|
foldersMut: sync.NewMutex(),
|
||||||
@ -144,8 +146,8 @@ func (c *folderSummaryService) OnEventRequest() {
|
|||||||
// listenForUpdates subscribes to the event bus and makes note of folders that
|
// listenForUpdates subscribes to the event bus and makes note of folders that
|
||||||
// need their data recalculated.
|
// need their data recalculated.
|
||||||
func (c *folderSummaryService) listenForUpdates(stop chan struct{}) {
|
func (c *folderSummaryService) listenForUpdates(stop chan struct{}) {
|
||||||
sub := events.Default.Subscribe(events.LocalIndexUpdated | events.RemoteIndexUpdated | events.StateChanged | events.RemoteDownloadProgress | events.DeviceConnected | events.FolderWatchStateChanged | events.DownloadProgress)
|
sub := c.evLogger.Subscribe(events.LocalIndexUpdated | events.RemoteIndexUpdated | events.StateChanged | events.RemoteDownloadProgress | events.DeviceConnected | events.FolderWatchStateChanged | events.DownloadProgress)
|
||||||
defer events.Default.Unsubscribe(sub)
|
defer sub.Unsubscribe()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// This loop needs to be fast so we don't miss too many events.
|
// This loop needs to be fast so we don't miss too many events.
|
||||||
@ -291,7 +293,7 @@ func (c *folderSummaryService) sendSummary(folder string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
events.Default.Log(events.FolderSummary, map[string]interface{}{
|
c.evLogger.Log(events.FolderSummary, map[string]interface{}{
|
||||||
"folder": folder,
|
"folder": folder,
|
||||||
"summary": data,
|
"summary": data,
|
||||||
})
|
})
|
||||||
@ -311,6 +313,6 @@ func (c *folderSummaryService) sendSummary(folder string) {
|
|||||||
comp := c.model.Completion(devCfg.DeviceID, folder).Map()
|
comp := c.model.Completion(devCfg.DeviceID, folder).Map()
|
||||||
comp["folder"] = folder
|
comp["folder"] = folder
|
||||||
comp["device"] = devCfg.DeviceID.String()
|
comp["device"] = devCfg.DeviceID.String()
|
||||||
events.Default.Log(events.FolderCompletion, comp)
|
c.evLogger.Log(events.FolderCompletion, comp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,6 +42,7 @@ func (s folderState) String() string {
|
|||||||
|
|
||||||
type stateTracker struct {
|
type stateTracker struct {
|
||||||
folderID string
|
folderID string
|
||||||
|
evLogger events.Logger
|
||||||
|
|
||||||
mut sync.Mutex
|
mut sync.Mutex
|
||||||
current folderState
|
current folderState
|
||||||
@ -49,9 +50,10 @@ type stateTracker struct {
|
|||||||
changed time.Time
|
changed time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStateTracker(id string) stateTracker {
|
func newStateTracker(id string, evLogger events.Logger) stateTracker {
|
||||||
return stateTracker{
|
return stateTracker{
|
||||||
folderID: id,
|
folderID: id,
|
||||||
|
evLogger: evLogger,
|
||||||
mut: sync.NewMutex(),
|
mut: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,7 +85,7 @@ func (s *stateTracker) setState(newState folderState) {
|
|||||||
s.current = newState
|
s.current = newState
|
||||||
s.changed = time.Now()
|
s.changed = time.Now()
|
||||||
|
|
||||||
events.Default.Log(events.StateChanged, eventData)
|
s.evLogger.Log(events.StateChanged, eventData)
|
||||||
}
|
}
|
||||||
s.mut.Unlock()
|
s.mut.Unlock()
|
||||||
}
|
}
|
||||||
@ -124,5 +126,5 @@ func (s *stateTracker) setError(err error) {
|
|||||||
s.err = err
|
s.err = err
|
||||||
s.changed = time.Now()
|
s.changed = time.Now()
|
||||||
|
|
||||||
events.Default.Log(events.StateChanged, eventData)
|
s.evLogger.Log(events.StateChanged, eventData)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -128,6 +128,7 @@ type model struct {
|
|||||||
shortID protocol.ShortID
|
shortID protocol.ShortID
|
||||||
cacheIgnoredFiles bool
|
cacheIgnoredFiles bool
|
||||||
protectedFiles []string
|
protectedFiles []string
|
||||||
|
evLogger events.Logger
|
||||||
|
|
||||||
clientName string
|
clientName string
|
||||||
clientVersion string
|
clientVersion string
|
||||||
@ -152,7 +153,7 @@ type model struct {
|
|||||||
foldersRunning int32 // for testing only
|
foldersRunning int32 // for testing only
|
||||||
}
|
}
|
||||||
|
|
||||||
type folderFactory func(*model, *db.FileSet, *ignore.Matcher, config.FolderConfiguration, versioner.Versioner, fs.Filesystem) service
|
type folderFactory func(*model, *db.FileSet, *ignore.Matcher, config.FolderConfiguration, versioner.Versioner, fs.Filesystem, events.Logger) service
|
||||||
|
|
||||||
var (
|
var (
|
||||||
folderFactories = make(map[config.FolderType]folderFactory)
|
folderFactories = make(map[config.FolderType]folderFactory)
|
||||||
@ -175,7 +176,7 @@ var (
|
|||||||
// NewModel creates and starts a new model. The model starts in read-only mode,
|
// NewModel creates and starts a new model. The model starts in read-only mode,
|
||||||
// where it sends index information to connected peers and responds to requests
|
// where it sends index information to connected peers and responds to requests
|
||||||
// for file data without altering the local folder in any way.
|
// for file data without altering the local folder in any way.
|
||||||
func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersion string, ldb *db.Lowlevel, protectedFiles []string) Model {
|
func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersion string, ldb *db.Lowlevel, protectedFiles []string, evLogger events.Logger) Model {
|
||||||
m := &model{
|
m := &model{
|
||||||
Supervisor: suture.New("model", suture.Spec{
|
Supervisor: suture.New("model", suture.Spec{
|
||||||
Log: func(line string) {
|
Log: func(line string) {
|
||||||
@ -186,11 +187,12 @@ func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersio
|
|||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
db: ldb,
|
db: ldb,
|
||||||
finder: db.NewBlockFinder(ldb),
|
finder: db.NewBlockFinder(ldb),
|
||||||
progressEmitter: NewProgressEmitter(cfg),
|
progressEmitter: NewProgressEmitter(cfg, evLogger),
|
||||||
id: id,
|
id: id,
|
||||||
shortID: id.Short(),
|
shortID: id.Short(),
|
||||||
cacheIgnoredFiles: cfg.Options().CacheIgnoredFiles,
|
cacheIgnoredFiles: cfg.Options().CacheIgnoredFiles,
|
||||||
protectedFiles: protectedFiles,
|
protectedFiles: protectedFiles,
|
||||||
|
evLogger: evLogger,
|
||||||
clientName: clientName,
|
clientName: clientName,
|
||||||
clientVersion: clientVersion,
|
clientVersion: clientVersion,
|
||||||
folderCfgs: make(map[string]config.FolderConfiguration),
|
folderCfgs: make(map[string]config.FolderConfiguration),
|
||||||
@ -310,7 +312,7 @@ func (m *model) startFolderLocked(cfg config.FolderConfiguration) {
|
|||||||
ffs.Hide(".stversions")
|
ffs.Hide(".stversions")
|
||||||
ffs.Hide(".stignore")
|
ffs.Hide(".stignore")
|
||||||
|
|
||||||
p := folderFactory(m, fset, m.folderIgnores[folder], cfg, ver, ffs)
|
p := folderFactory(m, fset, m.folderIgnores[folder], cfg, ver, ffs, m.evLogger)
|
||||||
|
|
||||||
m.folderRunners[folder] = p
|
m.folderRunners[folder] = p
|
||||||
|
|
||||||
@ -1023,7 +1025,7 @@ func (m *model) handleIndex(deviceID protocol.DeviceID, folder string, fs []prot
|
|||||||
}
|
}
|
||||||
files.Update(deviceID, fs)
|
files.Update(deviceID, fs)
|
||||||
|
|
||||||
events.Default.Log(events.RemoteIndexUpdated, map[string]interface{}{
|
m.evLogger.Log(events.RemoteIndexUpdated, map[string]interface{}{
|
||||||
"device": deviceID.String(),
|
"device": deviceID.String(),
|
||||||
"folder": folder,
|
"folder": folder,
|
||||||
"items": len(fs),
|
"items": len(fs),
|
||||||
@ -1077,7 +1079,7 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
|
|||||||
}
|
}
|
||||||
m.cfg.AddOrUpdatePendingFolder(folder.ID, folder.Label, deviceID)
|
m.cfg.AddOrUpdatePendingFolder(folder.ID, folder.Label, deviceID)
|
||||||
changed = true
|
changed = true
|
||||||
events.Default.Log(events.FolderRejected, map[string]string{
|
m.evLogger.Log(events.FolderRejected, map[string]string{
|
||||||
"folder": folder.ID,
|
"folder": folder.ID,
|
||||||
"folderLabel": folder.Label,
|
"folderLabel": folder.Label,
|
||||||
"device": deviceID.String(),
|
"device": deviceID.String(),
|
||||||
@ -1180,6 +1182,7 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
|
|||||||
fset: fs,
|
fset: fs,
|
||||||
prevSequence: startSequence,
|
prevSequence: startSequence,
|
||||||
dropSymlinks: dropSymlinks,
|
dropSymlinks: dropSymlinks,
|
||||||
|
evLogger: m.evLogger,
|
||||||
}
|
}
|
||||||
is.Service = util.AsService(is.serve)
|
is.Service = util.AsService(is.serve)
|
||||||
// The token isn't tracked as the service stops when the connection
|
// The token isn't tracked as the service stops when the connection
|
||||||
@ -1432,7 +1435,7 @@ func (m *model) Closed(conn protocol.Connection, err error) {
|
|||||||
delete(m.closed, device)
|
delete(m.closed, device)
|
||||||
|
|
||||||
l.Infof("Connection to %s at %s closed: %v", device, conn.Name(), err)
|
l.Infof("Connection to %s at %s closed: %v", device, conn.Name(), err)
|
||||||
events.Default.Log(events.DeviceDisconnected, map[string]string{
|
m.evLogger.Log(events.DeviceDisconnected, map[string]string{
|
||||||
"id": device.String(),
|
"id": device.String(),
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
})
|
})
|
||||||
@ -1773,7 +1776,7 @@ func (m *model) OnHello(remoteID protocol.DeviceID, addr net.Addr, hello protoco
|
|||||||
if !ok {
|
if !ok {
|
||||||
m.cfg.AddOrUpdatePendingDevice(remoteID, hello.DeviceName, addr.String())
|
m.cfg.AddOrUpdatePendingDevice(remoteID, hello.DeviceName, addr.String())
|
||||||
_ = m.cfg.Save() // best effort
|
_ = m.cfg.Save() // best effort
|
||||||
events.Default.Log(events.DeviceRejected, map[string]string{
|
m.evLogger.Log(events.DeviceRejected, map[string]string{
|
||||||
"name": hello.DeviceName,
|
"name": hello.DeviceName,
|
||||||
"device": remoteID.String(),
|
"device": remoteID.String(),
|
||||||
"address": addr.String(),
|
"address": addr.String(),
|
||||||
@ -1859,7 +1862,7 @@ func (m *model) AddConnection(conn connections.Connection, hello protocol.HelloR
|
|||||||
event["addr"] = addr.String()
|
event["addr"] = addr.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
events.Default.Log(events.DeviceConnected, event)
|
m.evLogger.Log(events.DeviceConnected, event)
|
||||||
|
|
||||||
l.Infof(`Device %s client is "%s %s" named "%s" at %s`, deviceID, hello.ClientName, hello.ClientVersion, hello.DeviceName, conn)
|
l.Infof(`Device %s client is "%s %s" named "%s" at %s`, deviceID, hello.ClientName, hello.ClientVersion, hello.DeviceName, conn)
|
||||||
|
|
||||||
@ -1894,7 +1897,7 @@ func (m *model) DownloadProgress(device protocol.DeviceID, folder string, update
|
|||||||
downloads.Update(folder, updates)
|
downloads.Update(folder, updates)
|
||||||
state := downloads.GetBlockCounts(folder)
|
state := downloads.GetBlockCounts(folder)
|
||||||
|
|
||||||
events.Default.Log(events.RemoteDownloadProgress, map[string]interface{}{
|
m.evLogger.Log(events.RemoteDownloadProgress, map[string]interface{}{
|
||||||
"device": device.String(),
|
"device": device.String(),
|
||||||
"folder": folder,
|
"folder": folder,
|
||||||
"state": state,
|
"state": state,
|
||||||
@ -1926,6 +1929,7 @@ type indexSender struct {
|
|||||||
fset *db.FileSet
|
fset *db.FileSet
|
||||||
prevSequence int64
|
prevSequence int64
|
||||||
dropSymlinks bool
|
dropSymlinks bool
|
||||||
|
evLogger events.Logger
|
||||||
connClosed chan struct{}
|
connClosed chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1941,8 +1945,8 @@ func (s *indexSender) serve(stop chan struct{}) {
|
|||||||
// Subscribe to LocalIndexUpdated (we have new information to send) and
|
// Subscribe to LocalIndexUpdated (we have new information to send) and
|
||||||
// DeviceDisconnected (it might be us who disconnected, so we should
|
// DeviceDisconnected (it might be us who disconnected, so we should
|
||||||
// exit).
|
// exit).
|
||||||
sub := events.Default.Subscribe(events.LocalIndexUpdated | events.DeviceDisconnected)
|
sub := s.evLogger.Subscribe(events.LocalIndexUpdated | events.DeviceDisconnected)
|
||||||
defer events.Default.Unsubscribe(sub)
|
defer sub.Unsubscribe()
|
||||||
|
|
||||||
evChan := sub.C()
|
evChan := sub.C()
|
||||||
ticker := time.NewTicker(time.Minute)
|
ticker := time.NewTicker(time.Minute)
|
||||||
@ -2531,7 +2535,7 @@ func (m *model) CommitConfiguration(from, to config.Configuration) bool {
|
|||||||
if toCfg.Paused {
|
if toCfg.Paused {
|
||||||
eventType = events.FolderPaused
|
eventType = events.FolderPaused
|
||||||
}
|
}
|
||||||
events.Default.Log(eventType, map[string]string{"id": toCfg.ID, "label": toCfg.Label})
|
m.evLogger.Log(eventType, map[string]string{"id": toCfg.ID, "label": toCfg.Label})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2559,9 +2563,9 @@ func (m *model) CommitConfiguration(from, to config.Configuration) bool {
|
|||||||
if toCfg.Paused {
|
if toCfg.Paused {
|
||||||
l.Infoln("Pausing", deviceID)
|
l.Infoln("Pausing", deviceID)
|
||||||
m.closeConn(deviceID, errDevicePaused)
|
m.closeConn(deviceID, errDevicePaused)
|
||||||
events.Default.Log(events.DevicePaused, map[string]string{"device": deviceID.String()})
|
m.evLogger.Log(events.DevicePaused, map[string]string{"device": deviceID.String()})
|
||||||
} else {
|
} else {
|
||||||
events.Default.Log(events.DeviceResumed, map[string]string{"device": deviceID.String()})
|
m.evLogger.Log(events.DeviceResumed, map[string]string{"device": deviceID.String()})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -110,7 +110,7 @@ func createTmpWrapper(cfg config.Configuration) config.Wrapper {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
wrapper := config.Wrap(tmpFile.Name(), cfg)
|
wrapper := config.Wrap(tmpFile.Name(), cfg, events.NoopLogger)
|
||||||
tmpFile.Close()
|
tmpFile.Close()
|
||||||
return wrapper
|
return wrapper
|
||||||
}
|
}
|
||||||
@ -303,7 +303,7 @@ func TestDeviceRename(t *testing.T) {
|
|||||||
DeviceID: device1,
|
DeviceID: device1,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cfg := config.Wrap("testdata/tmpconfig.xml", rawCfg)
|
cfg := config.Wrap("testdata/tmpconfig.xml", rawCfg, events.NoopLogger)
|
||||||
|
|
||||||
db := db.OpenMemory()
|
db := db.OpenMemory()
|
||||||
m := newModel(cfg, myID, "syncthing", "dev", db, nil)
|
m := newModel(cfg, myID, "syncthing", "dev", db, nil)
|
||||||
@ -339,7 +339,7 @@ func TestDeviceRename(t *testing.T) {
|
|||||||
t.Errorf("Device name got overwritten")
|
t.Errorf("Device name got overwritten")
|
||||||
}
|
}
|
||||||
|
|
||||||
cfgw, err := config.Load("testdata/tmpconfig.xml", myID)
|
cfgw, err := config.Load("testdata/tmpconfig.xml", myID, events.NoopLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
@ -3358,12 +3358,12 @@ func TestModTimeWindow(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDevicePause(t *testing.T) {
|
func TestDevicePause(t *testing.T) {
|
||||||
sub := events.Default.Subscribe(events.DevicePaused)
|
|
||||||
defer events.Default.Unsubscribe(sub)
|
|
||||||
|
|
||||||
m, _, fcfg := setupModelWithConnection()
|
m, _, fcfg := setupModelWithConnection()
|
||||||
defer cleanupModelAndRemoveDir(m, fcfg.Filesystem().URI())
|
defer cleanupModelAndRemoveDir(m, fcfg.Filesystem().URI())
|
||||||
|
|
||||||
|
sub := m.evLogger.Subscribe(events.DevicePaused)
|
||||||
|
defer sub.Unsubscribe()
|
||||||
|
|
||||||
m.pmut.RLock()
|
m.pmut.RLock()
|
||||||
closed := m.closed[device1]
|
closed := m.closed[device1]
|
||||||
m.pmut.RUnlock()
|
m.pmut.RUnlock()
|
||||||
|
|||||||
@ -29,6 +29,7 @@ type ProgressEmitter struct {
|
|||||||
connections map[protocol.DeviceID]protocol.Connection
|
connections map[protocol.DeviceID]protocol.Connection
|
||||||
foldersByConns map[protocol.DeviceID][]string
|
foldersByConns map[protocol.DeviceID][]string
|
||||||
disabled bool
|
disabled bool
|
||||||
|
evLogger events.Logger
|
||||||
mut sync.Mutex
|
mut sync.Mutex
|
||||||
|
|
||||||
timer *time.Timer
|
timer *time.Timer
|
||||||
@ -36,13 +37,14 @@ type ProgressEmitter struct {
|
|||||||
|
|
||||||
// NewProgressEmitter creates a new progress emitter which emits
|
// NewProgressEmitter creates a new progress emitter which emits
|
||||||
// DownloadProgress events every interval.
|
// DownloadProgress events every interval.
|
||||||
func NewProgressEmitter(cfg config.Wrapper) *ProgressEmitter {
|
func NewProgressEmitter(cfg config.Wrapper, evLogger events.Logger) *ProgressEmitter {
|
||||||
t := &ProgressEmitter{
|
t := &ProgressEmitter{
|
||||||
registry: make(map[string]map[string]*sharedPullerState),
|
registry: make(map[string]map[string]*sharedPullerState),
|
||||||
timer: time.NewTimer(time.Millisecond),
|
timer: time.NewTimer(time.Millisecond),
|
||||||
sentDownloadStates: make(map[protocol.DeviceID]*sentDownloadState),
|
sentDownloadStates: make(map[protocol.DeviceID]*sentDownloadState),
|
||||||
connections: make(map[protocol.DeviceID]protocol.Connection),
|
connections: make(map[protocol.DeviceID]protocol.Connection),
|
||||||
foldersByConns: make(map[protocol.DeviceID][]string),
|
foldersByConns: make(map[protocol.DeviceID][]string),
|
||||||
|
evLogger: evLogger,
|
||||||
mut: sync.NewMutex(),
|
mut: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
t.Service = util.AsService(t.serve)
|
t.Service = util.AsService(t.serve)
|
||||||
@ -107,7 +109,7 @@ func (t *ProgressEmitter) sendDownloadProgressEventLocked() {
|
|||||||
output[folder][name] = puller.Progress()
|
output[folder][name] = puller.Progress()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
events.Default.Log(events.DownloadProgress, output)
|
t.evLogger.Log(events.DownloadProgress, output)
|
||||||
l.Debugf("progress emitter: emitting %#v", output)
|
l.Debugf("progress emitter: emitting %#v", output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,7 +30,7 @@ func caller(skip int) string {
|
|||||||
return fmt.Sprintf("%s:%d", filepath.Base(file), line)
|
return fmt.Sprintf("%s:%d", filepath.Base(file), line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectEvent(w *events.Subscription, t *testing.T, size int) {
|
func expectEvent(w events.Subscription, t *testing.T, size int) {
|
||||||
event, err := w.Poll(timeout)
|
event, err := w.Poll(timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Unexpected error:", err, "at", caller(1))
|
t.Fatal("Unexpected error:", err, "at", caller(1))
|
||||||
@ -44,7 +44,7 @@ func expectEvent(w *events.Subscription, t *testing.T, size int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectTimeout(w *events.Subscription, t *testing.T) {
|
func expectTimeout(w events.Subscription, t *testing.T) {
|
||||||
_, err := w.Poll(timeout)
|
_, err := w.Poll(timeout)
|
||||||
if err != events.ErrTimeout {
|
if err != events.ErrTimeout {
|
||||||
t.Fatal("Unexpected non-Timeout error:", err, "at", caller(1))
|
t.Fatal("Unexpected non-Timeout error:", err, "at", caller(1))
|
||||||
@ -52,7 +52,11 @@ func expectTimeout(w *events.Subscription, t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestProgressEmitter(t *testing.T) {
|
func TestProgressEmitter(t *testing.T) {
|
||||||
w := events.Default.Subscribe(events.DownloadProgress)
|
evLogger := events.NewLogger()
|
||||||
|
go evLogger.Serve()
|
||||||
|
defer evLogger.Stop()
|
||||||
|
|
||||||
|
w := evLogger.Subscribe(events.DownloadProgress)
|
||||||
|
|
||||||
c := createTmpWrapper(config.Configuration{})
|
c := createTmpWrapper(config.Configuration{})
|
||||||
defer os.Remove(c.ConfigPath())
|
defer os.Remove(c.ConfigPath())
|
||||||
@ -60,7 +64,7 @@ func TestProgressEmitter(t *testing.T) {
|
|||||||
ProgressUpdateIntervalS: 0,
|
ProgressUpdateIntervalS: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
p := NewProgressEmitter(c)
|
p := NewProgressEmitter(c, evLogger)
|
||||||
go p.Serve()
|
go p.Serve()
|
||||||
p.interval = 0
|
p.interval = 0
|
||||||
|
|
||||||
@ -112,7 +116,11 @@ func TestSendDownloadProgressMessages(t *testing.T) {
|
|||||||
|
|
||||||
fc := &fakeConnection{}
|
fc := &fakeConnection{}
|
||||||
|
|
||||||
p := NewProgressEmitter(c)
|
evLogger := events.NewLogger()
|
||||||
|
go evLogger.Serve()
|
||||||
|
defer evLogger.Stop()
|
||||||
|
|
||||||
|
p := NewProgressEmitter(c, evLogger)
|
||||||
p.temporaryIndexSubscribe(fc, []string{"folder", "folder2"})
|
p.temporaryIndexSubscribe(fc, []string{"folder", "folder2"})
|
||||||
p.registry["folder"] = make(map[string]*sharedPullerState)
|
p.registry["folder"] = make(map[string]*sharedPullerState)
|
||||||
p.registry["folder2"] = make(map[string]*sharedPullerState)
|
p.registry["folder2"] = make(map[string]*sharedPullerState)
|
||||||
|
|||||||
@ -350,8 +350,8 @@ func pullInvalidIgnored(t *testing.T, ft config.FolderType) {
|
|||||||
}
|
}
|
||||||
fc.mut.Unlock()
|
fc.mut.Unlock()
|
||||||
|
|
||||||
sub := events.Default.Subscribe(events.FolderErrors)
|
sub := m.evLogger.Subscribe(events.FolderErrors)
|
||||||
defer events.Default.Unsubscribe(sub)
|
defer sub.Unsubscribe()
|
||||||
|
|
||||||
fc.sendIndexUpdate()
|
fc.sendIndexUpdate()
|
||||||
|
|
||||||
@ -640,8 +640,8 @@ func TestRequestSymlinkWindows(t *testing.T) {
|
|||||||
t.Fatalf("timed out before pull was finished")
|
t.Fatalf("timed out before pull was finished")
|
||||||
}
|
}
|
||||||
|
|
||||||
sub := events.Default.Subscribe(events.StateChanged | events.LocalIndexUpdated)
|
sub := m.evLogger.Subscribe(events.StateChanged | events.LocalIndexUpdated)
|
||||||
defer events.Default.Unsubscribe(sub)
|
defer sub.Unsubscribe()
|
||||||
|
|
||||||
m.ScanFolder("default")
|
m.ScanFolder("default")
|
||||||
|
|
||||||
@ -978,8 +978,8 @@ func TestNeedFolderFiles(t *testing.T) {
|
|||||||
tmpDir := tfs.URI()
|
tmpDir := tfs.URI()
|
||||||
defer cleanupModelAndRemoveDir(m, tmpDir)
|
defer cleanupModelAndRemoveDir(m, tmpDir)
|
||||||
|
|
||||||
sub := events.Default.Subscribe(events.RemoteIndexUpdated)
|
sub := m.evLogger.Subscribe(events.RemoteIndexUpdated)
|
||||||
defer events.Default.Unsubscribe(sub)
|
defer sub.Unsubscribe()
|
||||||
|
|
||||||
errPreventSync := errors.New("you aren't getting any of this")
|
errPreventSync := errors.New("you aren't getting any of this")
|
||||||
fc.mut.Lock()
|
fc.mut.Lock()
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
"github.com/syncthing/syncthing/lib/config"
|
"github.com/syncthing/syncthing/lib/config"
|
||||||
"github.com/syncthing/syncthing/lib/db"
|
"github.com/syncthing/syncthing/lib/db"
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/fs"
|
"github.com/syncthing/syncthing/lib/fs"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
)
|
)
|
||||||
@ -117,12 +118,16 @@ func setupModel(w config.Wrapper) *model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersion string, ldb *db.Lowlevel, protectedFiles []string) *model {
|
func newModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersion string, ldb *db.Lowlevel, protectedFiles []string) *model {
|
||||||
return NewModel(cfg, id, clientName, clientVersion, ldb, protectedFiles).(*model)
|
evLogger := events.NewLogger()
|
||||||
|
m := NewModel(cfg, id, clientName, clientVersion, ldb, protectedFiles, evLogger).(*model)
|
||||||
|
go evLogger.Serve()
|
||||||
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanupModel(m *model) {
|
func cleanupModel(m *model) {
|
||||||
m.Stop()
|
m.Stop()
|
||||||
m.db.Close()
|
m.db.Close()
|
||||||
|
m.evLogger.Stop()
|
||||||
os.Remove(m.cfg.ConfigPath())
|
os.Remove(m.cfg.ConfigPath())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import (
|
|||||||
|
|
||||||
"github.com/syncthing/syncthing/lib/config"
|
"github.com/syncthing/syncthing/lib/config"
|
||||||
"github.com/syncthing/syncthing/lib/dialer"
|
"github.com/syncthing/syncthing/lib/dialer"
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
"github.com/syncthing/syncthing/lib/sync"
|
"github.com/syncthing/syncthing/lib/sync"
|
||||||
)
|
)
|
||||||
@ -455,7 +456,7 @@ func (p *Process) eventLoop() {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
events, err := p.Events(since)
|
evs, err := p.Events(since)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if time.Since(start) < 5*time.Second {
|
if time.Since(start) < 5*time.Second {
|
||||||
// The API has probably not started yet, lets give it some time.
|
// The API has probably not started yet, lets give it some time.
|
||||||
@ -473,7 +474,7 @@ func (p *Process) eventLoop() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ev := range events {
|
for _, ev := range evs {
|
||||||
if ev.ID != since+1 {
|
if ev.ID != since+1 {
|
||||||
l.Warnln("Event ID jumped", since, "to", ev.ID)
|
l.Warnln("Event ID jumped", since, "to", ev.ID)
|
||||||
}
|
}
|
||||||
@ -493,7 +494,7 @@ func (p *Process) eventLoop() {
|
|||||||
p.id = id
|
p.id = id
|
||||||
|
|
||||||
home := data["home"].(string)
|
home := data["home"].(string)
|
||||||
w, err := config.Load(filepath.Join(home, "config.xml"), protocol.LocalDeviceID)
|
w, err := config.Load(filepath.Join(home, "config.xml"), protocol.LocalDeviceID, events.NoopLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("eventLoop: Starting:", err)
|
log.Println("eventLoop: Starting:", err)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -56,6 +56,8 @@ type Config struct {
|
|||||||
LocalFlags uint32
|
LocalFlags uint32
|
||||||
// Modification time is to be considered unchanged if the difference is lower.
|
// Modification time is to be considered unchanged if the difference is lower.
|
||||||
ModTimeWindow time.Duration
|
ModTimeWindow time.Duration
|
||||||
|
// Event logger to which the scan progress events are sent
|
||||||
|
EvLogger events.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
type CurrentFiler interface {
|
type CurrentFiler interface {
|
||||||
@ -168,7 +170,7 @@ func (w *walker) walk(ctx context.Context) chan ScanResult {
|
|||||||
current := progress.Total()
|
current := progress.Total()
|
||||||
rate := progress.Rate()
|
rate := progress.Rate()
|
||||||
l.Debugf("Walk %s %s current progress %d/%d at %.01f MiB/s (%d%%)", w.Folder, w.Subs, current, total, rate/1024/1024, current*100/total)
|
l.Debugf("Walk %s %s current progress %d/%d at %.01f MiB/s (%d%%)", w.Folder, w.Subs, current, total, rate/1024/1024, current*100/total)
|
||||||
events.Default.Log(events.FolderScanProgress, map[string]interface{}{
|
w.EvLogger.Log(events.FolderScanProgress, map[string]interface{}{
|
||||||
"folder": w.Folder,
|
"folder": w.Folder,
|
||||||
"current": current,
|
"current": current,
|
||||||
"total": total,
|
"total": total,
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/d4l3k/messagediff"
|
"github.com/d4l3k/messagediff"
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/fs"
|
"github.com/syncthing/syncthing/lib/fs"
|
||||||
"github.com/syncthing/syncthing/lib/ignore"
|
"github.com/syncthing/syncthing/lib/ignore"
|
||||||
"github.com/syncthing/syncthing/lib/osutil"
|
"github.com/syncthing/syncthing/lib/osutil"
|
||||||
@ -66,12 +67,10 @@ func TestWalkSub(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fchan := Walk(context.TODO(), Config{
|
cfg := testConfig()
|
||||||
Filesystem: testFs,
|
cfg.Subs = []string{"dir2"}
|
||||||
Subs: []string{"dir2"},
|
cfg.Matcher = ignores
|
||||||
Matcher: ignores,
|
fchan := Walk(context.TODO(), cfg)
|
||||||
Hashers: 2,
|
|
||||||
})
|
|
||||||
var files []protocol.FileInfo
|
var files []protocol.FileInfo
|
||||||
for f := range fchan {
|
for f := range fchan {
|
||||||
if f.Err != nil {
|
if f.Err != nil {
|
||||||
@ -102,11 +101,9 @@ func TestWalk(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Log(ignores)
|
t.Log(ignores)
|
||||||
|
|
||||||
fchan := Walk(context.TODO(), Config{
|
cfg := testConfig()
|
||||||
Filesystem: testFs,
|
cfg.Matcher = ignores
|
||||||
Matcher: ignores,
|
fchan := Walk(context.TODO(), cfg)
|
||||||
Hashers: 2,
|
|
||||||
})
|
|
||||||
|
|
||||||
var tmp []protocol.FileInfo
|
var tmp []protocol.FileInfo
|
||||||
for f := range fchan {
|
for f := range fchan {
|
||||||
@ -466,15 +463,14 @@ func TestWalkReceiveOnly(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func walkDir(fs fs.Filesystem, dir string, cfiler CurrentFiler, matcher *ignore.Matcher, localFlags uint32) []protocol.FileInfo {
|
func walkDir(fs fs.Filesystem, dir string, cfiler CurrentFiler, matcher *ignore.Matcher, localFlags uint32) []protocol.FileInfo {
|
||||||
fchan := Walk(context.TODO(), Config{
|
cfg := testConfig()
|
||||||
Filesystem: fs,
|
cfg.Filesystem = fs
|
||||||
Subs: []string{dir},
|
cfg.Subs = []string{dir}
|
||||||
AutoNormalize: true,
|
cfg.AutoNormalize = true
|
||||||
Hashers: 2,
|
cfg.CurrentFiler = cfiler
|
||||||
CurrentFiler: cfiler,
|
cfg.Matcher = matcher
|
||||||
Matcher: matcher,
|
cfg.LocalFlags = localFlags
|
||||||
LocalFlags: localFlags,
|
fchan := Walk(context.TODO(), cfg)
|
||||||
})
|
|
||||||
|
|
||||||
var tmp []protocol.FileInfo
|
var tmp []protocol.FileInfo
|
||||||
for f := range fchan {
|
for f := range fchan {
|
||||||
@ -576,11 +572,11 @@ func TestStopWalk(t *testing.T) {
|
|||||||
|
|
||||||
const numHashers = 4
|
const numHashers = 4
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
fchan := Walk(ctx, Config{
|
cfg := testConfig()
|
||||||
Filesystem: fs,
|
cfg.Filesystem = fs
|
||||||
Hashers: numHashers,
|
cfg.Hashers = numHashers
|
||||||
ProgressTickIntervalS: -1, // Don't attempt to build the full list of files before starting to scan...
|
cfg.ProgressTickIntervalS = -1 // Don't attempt to build the full list of files before starting to scan...
|
||||||
})
|
fchan := Walk(ctx, cfg)
|
||||||
|
|
||||||
// Receive a few entries to make sure the walker is up and running,
|
// Receive a few entries to make sure the walker is up and running,
|
||||||
// scanning both files and dirs. Do some quick sanity tests on the
|
// scanning both files and dirs. Do some quick sanity tests on the
|
||||||
@ -705,21 +701,17 @@ func TestIssue4841(t *testing.T) {
|
|||||||
}
|
}
|
||||||
fd.Close()
|
fd.Close()
|
||||||
|
|
||||||
fchan := Walk(context.TODO(), Config{
|
cfg := testConfig()
|
||||||
Filesystem: fs,
|
cfg.Filesystem = fs
|
||||||
Subs: nil,
|
cfg.AutoNormalize = true
|
||||||
AutoNormalize: true,
|
cfg.CurrentFiler = fakeCurrentFiler{"foo": {
|
||||||
Hashers: 2,
|
|
||||||
CurrentFiler: fakeCurrentFiler{
|
|
||||||
"foo": {
|
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Type: protocol.FileInfoTypeFile,
|
Type: protocol.FileInfoTypeFile,
|
||||||
LocalFlags: protocol.FlagLocalIgnored,
|
LocalFlags: protocol.FlagLocalIgnored,
|
||||||
Version: protocol.Vector{}.Update(1),
|
Version: protocol.Vector{}.Update(1),
|
||||||
},
|
}}
|
||||||
},
|
cfg.ShortID = protocol.LocalDeviceID.Short()
|
||||||
ShortID: protocol.LocalDeviceID.Short(),
|
fchan := Walk(context.TODO(), cfg)
|
||||||
})
|
|
||||||
|
|
||||||
var files []protocol.FileInfo
|
var files []protocol.FileInfo
|
||||||
for f := range fchan {
|
for f := range fchan {
|
||||||
@ -745,11 +737,9 @@ func TestNotExistingError(t *testing.T) {
|
|||||||
t.Fatalf("Lstat returned error %v, while nothing should exist there.", err)
|
t.Fatalf("Lstat returned error %v, while nothing should exist there.", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fchan := Walk(context.TODO(), Config{
|
cfg := testConfig()
|
||||||
Filesystem: testFs,
|
cfg.Subs = []string{sub}
|
||||||
Subs: []string{sub},
|
fchan := Walk(context.TODO(), cfg)
|
||||||
Hashers: 2,
|
|
||||||
})
|
|
||||||
for f := range fchan {
|
for f := range fchan {
|
||||||
t.Fatalf("Expected no result from scan, got %v", f)
|
t.Fatalf("Expected no result from scan, got %v", f)
|
||||||
}
|
}
|
||||||
@ -793,3 +783,13 @@ func (fcf fakeCurrentFiler) CurrentFile(name string) (protocol.FileInfo, bool) {
|
|||||||
f, ok := fcf[name]
|
f, ok := fcf[name]
|
||||||
return f, ok
|
return f, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testConfig() Config {
|
||||||
|
evLogger := events.NewLogger()
|
||||||
|
go evLogger.Serve()
|
||||||
|
return Config{
|
||||||
|
Filesystem: testFs,
|
||||||
|
Hashers: 2,
|
||||||
|
EvLogger: evLogger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -21,13 +21,13 @@ import (
|
|||||||
type auditService struct {
|
type auditService struct {
|
||||||
suture.Service
|
suture.Service
|
||||||
w io.Writer // audit destination
|
w io.Writer // audit destination
|
||||||
sub *events.Subscription
|
sub events.Subscription
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAuditService(w io.Writer) *auditService {
|
func newAuditService(w io.Writer, evLogger events.Logger) *auditService {
|
||||||
s := &auditService{
|
s := &auditService{
|
||||||
w: w,
|
w: w,
|
||||||
sub: events.Default.Subscribe(events.AllEvents),
|
sub: evLogger.Subscribe(events.AllEvents),
|
||||||
}
|
}
|
||||||
s.Service = util.AsService(s.serve)
|
s.Service = util.AsService(s.serve)
|
||||||
return s
|
return s
|
||||||
@ -50,5 +50,5 @@ func (s *auditService) serve(stop chan struct{}) {
|
|||||||
// Stop stops the audit service.
|
// Stop stops the audit service.
|
||||||
func (s *auditService) Stop() {
|
func (s *auditService) Stop() {
|
||||||
s.Service.Stop()
|
s.Service.Stop()
|
||||||
events.Default.Unsubscribe(s.sub)
|
s.sub.Unsubscribe()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,15 +17,22 @@ import (
|
|||||||
|
|
||||||
func TestAuditService(t *testing.T) {
|
func TestAuditService(t *testing.T) {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
|
evLogger := events.NewLogger()
|
||||||
|
go evLogger.Serve()
|
||||||
|
defer evLogger.Stop()
|
||||||
|
sub := evLogger.Subscribe(events.AllEvents)
|
||||||
|
defer sub.Unsubscribe()
|
||||||
|
|
||||||
// Event sent before construction, will not be logged
|
// Event sent before start, will not be logged
|
||||||
events.Default.Log(events.ConfigSaved, "the first event")
|
evLogger.Log(events.ConfigSaved, "the first event")
|
||||||
|
// Make sure the event goes through before creating the service
|
||||||
|
<-sub.C()
|
||||||
|
|
||||||
service := newAuditService(buf)
|
service := newAuditService(buf, evLogger)
|
||||||
go service.Serve()
|
go service.Serve()
|
||||||
|
|
||||||
// Event that should end up in the audit log
|
// Event that should end up in the audit log
|
||||||
events.Default.Log(events.ConfigSaved, "the second event")
|
evLogger.Log(events.ConfigSaved, "the second event")
|
||||||
|
|
||||||
// We need to give the events time to arrive, since the channels are buffered etc.
|
// We need to give the events time to arrive, since the channels are buffered etc.
|
||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(10 * time.Millisecond)
|
||||||
@ -33,7 +40,7 @@ func TestAuditService(t *testing.T) {
|
|||||||
service.Stop()
|
service.Stop()
|
||||||
|
|
||||||
// This event should not be logged, since we have stopped.
|
// This event should not be logged, since we have stopped.
|
||||||
events.Default.Log(events.ConfigSaved, "the third event")
|
evLogger.Log(events.ConfigSaved, "the third event")
|
||||||
|
|
||||||
result := buf.String()
|
result := buf.String()
|
||||||
t.Log(result)
|
t.Log(result)
|
||||||
|
|||||||
@ -68,6 +68,7 @@ type App struct {
|
|||||||
mainService *suture.Supervisor
|
mainService *suture.Supervisor
|
||||||
cfg config.Wrapper
|
cfg config.Wrapper
|
||||||
ll *db.Lowlevel
|
ll *db.Lowlevel
|
||||||
|
evLogger events.Logger
|
||||||
cert tls.Certificate
|
cert tls.Certificate
|
||||||
opts Options
|
opts Options
|
||||||
exitStatus ExitStatus
|
exitStatus ExitStatus
|
||||||
@ -78,10 +79,11 @@ type App struct {
|
|||||||
stopped chan struct{}
|
stopped chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg config.Wrapper, ll *db.Lowlevel, cert tls.Certificate, opts Options) *App {
|
func New(cfg config.Wrapper, ll *db.Lowlevel, evLogger events.Logger, cert tls.Certificate, opts Options) *App {
|
||||||
return &App{
|
return &App{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
ll: ll,
|
ll: ll,
|
||||||
|
evLogger: evLogger,
|
||||||
opts: opts,
|
opts: opts,
|
||||||
cert: cert,
|
cert: cert,
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
@ -120,11 +122,11 @@ func (a *App) startup() error {
|
|||||||
a.mainService.ServeBackground()
|
a.mainService.ServeBackground()
|
||||||
|
|
||||||
if a.opts.AuditWriter != nil {
|
if a.opts.AuditWriter != nil {
|
||||||
a.mainService.Add(newAuditService(a.opts.AuditWriter))
|
a.mainService.Add(newAuditService(a.opts.AuditWriter, a.evLogger))
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.opts.Verbose {
|
if a.opts.Verbose {
|
||||||
a.mainService.Add(newVerboseService())
|
a.mainService.Add(newVerboseService(a.evLogger))
|
||||||
}
|
}
|
||||||
|
|
||||||
errors := logger.NewRecorder(l, logger.LevelWarn, maxSystemErrors, 0)
|
errors := logger.NewRecorder(l, logger.LevelWarn, maxSystemErrors, 0)
|
||||||
@ -133,8 +135,8 @@ func (a *App) startup() error {
|
|||||||
// Event subscription for the API; must start early to catch the early
|
// Event subscription for the API; must start early to catch the early
|
||||||
// events. The LocalChangeDetected event might overwhelm the event
|
// events. The LocalChangeDetected event might overwhelm the event
|
||||||
// receiver in some situations so we will not subscribe to it here.
|
// receiver in some situations so we will not subscribe to it here.
|
||||||
defaultSub := events.NewBufferedSubscription(events.Default.Subscribe(api.DefaultEventMask), api.EventSubBufferSize)
|
defaultSub := events.NewBufferedSubscription(a.evLogger.Subscribe(api.DefaultEventMask), api.EventSubBufferSize)
|
||||||
diskSub := events.NewBufferedSubscription(events.Default.Subscribe(api.DiskEventMask), api.EventSubBufferSize)
|
diskSub := events.NewBufferedSubscription(a.evLogger.Subscribe(api.DiskEventMask), api.EventSubBufferSize)
|
||||||
|
|
||||||
// Attempt to increase the limit on number of open files to the maximum
|
// Attempt to increase the limit on number of open files to the maximum
|
||||||
// allowed, in case we have many peers. We don't really care enough to
|
// allowed, in case we have many peers. We don't really care enough to
|
||||||
@ -153,7 +155,7 @@ func (a *App) startup() error {
|
|||||||
|
|
||||||
// Emit the Starting event, now that we know who we are.
|
// Emit the Starting event, now that we know who we are.
|
||||||
|
|
||||||
events.Default.Log(events.Starting, map[string]string{
|
a.evLogger.Log(events.Starting, map[string]string{
|
||||||
"home": locations.GetBaseDir(locations.ConfigBaseDir),
|
"home": locations.GetBaseDir(locations.ConfigBaseDir),
|
||||||
"myID": a.myID.String(),
|
"myID": a.myID.String(),
|
||||||
})
|
})
|
||||||
@ -228,7 +230,7 @@ func (a *App) startup() error {
|
|||||||
miscDB.PutString("prevVersion", build.Version)
|
miscDB.PutString("prevVersion", build.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
m := model.NewModel(a.cfg, a.myID, "syncthing", build.Version, a.ll, protectedFiles)
|
m := model.NewModel(a.cfg, a.myID, "syncthing", build.Version, a.ll, protectedFiles, a.evLogger)
|
||||||
|
|
||||||
if a.opts.DeadlockTimeoutS > 0 {
|
if a.opts.DeadlockTimeoutS > 0 {
|
||||||
m.StartDeadlockDetector(time.Duration(a.opts.DeadlockTimeoutS) * time.Second)
|
m.StartDeadlockDetector(time.Duration(a.opts.DeadlockTimeoutS) * time.Second)
|
||||||
@ -265,13 +267,13 @@ func (a *App) startup() error {
|
|||||||
|
|
||||||
// Start connection management
|
// Start connection management
|
||||||
|
|
||||||
connectionsService := connections.NewService(a.cfg, a.myID, m, tlsCfg, cachedDiscovery, bepProtocolName, tlsDefaultCommonName)
|
connectionsService := connections.NewService(a.cfg, a.myID, m, tlsCfg, cachedDiscovery, bepProtocolName, tlsDefaultCommonName, a.evLogger)
|
||||||
a.mainService.Add(connectionsService)
|
a.mainService.Add(connectionsService)
|
||||||
|
|
||||||
if a.cfg.Options().GlobalAnnEnabled {
|
if a.cfg.Options().GlobalAnnEnabled {
|
||||||
for _, srv := range a.cfg.GlobalDiscoveryServers() {
|
for _, srv := range a.cfg.GlobalDiscoveryServers() {
|
||||||
l.Infoln("Using discovery server", srv)
|
l.Infoln("Using discovery server", srv)
|
||||||
gd, err := discover.NewGlobal(srv, a.cert, connectionsService)
|
gd, err := discover.NewGlobal(srv, a.cert, connectionsService, a.evLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Warnln("Global discovery:", err)
|
l.Warnln("Global discovery:", err)
|
||||||
continue
|
continue
|
||||||
@ -286,14 +288,14 @@ func (a *App) startup() error {
|
|||||||
|
|
||||||
if a.cfg.Options().LocalAnnEnabled {
|
if a.cfg.Options().LocalAnnEnabled {
|
||||||
// v4 broadcasts
|
// v4 broadcasts
|
||||||
bcd, err := discover.NewLocal(a.myID, fmt.Sprintf(":%d", a.cfg.Options().LocalAnnPort), connectionsService)
|
bcd, err := discover.NewLocal(a.myID, fmt.Sprintf(":%d", a.cfg.Options().LocalAnnPort), connectionsService, a.evLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Warnln("IPv4 local discovery:", err)
|
l.Warnln("IPv4 local discovery:", err)
|
||||||
} else {
|
} else {
|
||||||
cachedDiscovery.Add(bcd, 0, 0)
|
cachedDiscovery.Add(bcd, 0, 0)
|
||||||
}
|
}
|
||||||
// v6 multicasts
|
// v6 multicasts
|
||||||
mcd, err := discover.NewLocal(a.myID, a.cfg.Options().LocalAnnMCAddr, connectionsService)
|
mcd, err := discover.NewLocal(a.myID, a.cfg.Options().LocalAnnMCAddr, connectionsService, a.evLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Warnln("IPv6 local discovery:", err)
|
l.Warnln("IPv6 local discovery:", err)
|
||||||
} else {
|
} else {
|
||||||
@ -342,7 +344,7 @@ func (a *App) startup() error {
|
|||||||
l.Warnln("Syncthing should not run as a privileged or system user. Please consider using a normal user account.")
|
l.Warnln("Syncthing should not run as a privileged or system user. Please consider using a normal user account.")
|
||||||
}
|
}
|
||||||
|
|
||||||
events.Default.Log(events.StartupComplete, map[string]string{
|
a.evLogger.Log(events.StartupComplete, map[string]string{
|
||||||
"myID": a.myID.String(),
|
"myID": a.myID.String(),
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -426,10 +428,10 @@ func (a *App) setupGUI(m model.Model, defaultSub, diskSub events.BufferedSubscri
|
|||||||
cpu := newCPUService()
|
cpu := newCPUService()
|
||||||
a.mainService.Add(cpu)
|
a.mainService.Add(cpu)
|
||||||
|
|
||||||
summaryService := model.NewFolderSummaryService(a.cfg, m, a.myID)
|
summaryService := model.NewFolderSummaryService(a.cfg, m, a.myID, a.evLogger)
|
||||||
a.mainService.Add(summaryService)
|
a.mainService.Add(summaryService)
|
||||||
|
|
||||||
apiSvc := api.New(a.myID, a.cfg, a.opts.AssetDir, tlsDefaultCommonName, m, defaultSub, diskSub, discoverer, connectionsService, urService, summaryService, errors, systemLog, cpu, &controller{a}, a.opts.NoUpgrade)
|
apiSvc := api.New(a.myID, a.cfg, a.opts.AssetDir, tlsDefaultCommonName, m, defaultSub, diskSub, a.evLogger, discoverer, connectionsService, urService, summaryService, errors, systemLog, cpu, &controller{a}, a.opts.NoUpgrade)
|
||||||
a.mainService.Add(apiSvc)
|
a.mainService.Add(apiSvc)
|
||||||
|
|
||||||
if err := apiSvc.WaitForStart(); err != nil {
|
if err := apiSvc.WaitForStart(); err != nil {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/lib/config"
|
"github.com/syncthing/syncthing/lib/config"
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,7 +20,7 @@ func TestShortIDCheck(t *testing.T) {
|
|||||||
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 0, 0}},
|
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 0, 0}},
|
||||||
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 1, 1}}, // first 56 bits same, differ in the first 64 bits
|
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 1, 1}}, // first 56 bits same, differ in the first 64 bits
|
||||||
},
|
},
|
||||||
})
|
}, events.NoopLogger)
|
||||||
|
|
||||||
if err := checkShortIDs(cfg); err != nil {
|
if err := checkShortIDs(cfg); err != nil {
|
||||||
t.Error("Unexpected error:", err)
|
t.Error("Unexpected error:", err)
|
||||||
@ -30,7 +31,7 @@ func TestShortIDCheck(t *testing.T) {
|
|||||||
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 64, 0}},
|
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 64, 0}},
|
||||||
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 64, 1}}, // first 64 bits same
|
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 64, 1}}, // first 64 bits same
|
||||||
},
|
},
|
||||||
})
|
}, events.NoopLogger)
|
||||||
|
|
||||||
if err := checkShortIDs(cfg); err == nil {
|
if err := checkShortIDs(cfg); err == nil {
|
||||||
t.Error("Should have gotten an error")
|
t.Error("Should have gotten an error")
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import (
|
|||||||
|
|
||||||
"github.com/syncthing/syncthing/lib/config"
|
"github.com/syncthing/syncthing/lib/config"
|
||||||
"github.com/syncthing/syncthing/lib/db"
|
"github.com/syncthing/syncthing/lib/db"
|
||||||
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
"github.com/syncthing/syncthing/lib/fs"
|
"github.com/syncthing/syncthing/lib/fs"
|
||||||
"github.com/syncthing/syncthing/lib/locations"
|
"github.com/syncthing/syncthing/lib/locations"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
@ -39,7 +40,7 @@ func LoadOrGenerateCertificate(certFile, keyFile string) (tls.Certificate, error
|
|||||||
return cert, nil
|
return cert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DefaultConfig(path string, myID protocol.DeviceID, noDefaultFolder bool) (config.Wrapper, error) {
|
func DefaultConfig(path string, myID protocol.DeviceID, evLogger events.Logger, noDefaultFolder bool) (config.Wrapper, error) {
|
||||||
newCfg, err := config.NewWithFreePorts(myID)
|
newCfg, err := config.NewWithFreePorts(myID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -47,23 +48,23 @@ func DefaultConfig(path string, myID protocol.DeviceID, noDefaultFolder bool) (c
|
|||||||
|
|
||||||
if noDefaultFolder {
|
if noDefaultFolder {
|
||||||
l.Infoln("We will skip creation of a default folder on first start")
|
l.Infoln("We will skip creation of a default folder on first start")
|
||||||
return config.Wrap(path, newCfg), nil
|
return config.Wrap(path, newCfg, evLogger), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
newCfg.Folders = append(newCfg.Folders, config.NewFolderConfiguration(myID, "default", "Default Folder", fs.FilesystemTypeBasic, locations.Get(locations.DefFolder)))
|
newCfg.Folders = append(newCfg.Folders, config.NewFolderConfiguration(myID, "default", "Default Folder", fs.FilesystemTypeBasic, locations.Get(locations.DefFolder)))
|
||||||
l.Infoln("Default folder created and/or linked to new config")
|
l.Infoln("Default folder created and/or linked to new config")
|
||||||
return config.Wrap(path, newCfg), nil
|
return config.Wrap(path, newCfg, evLogger), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadConfigAtStartup loads an existing config. If it doesn't yet exist, it
|
// LoadConfigAtStartup loads an existing config. If it doesn't yet exist, it
|
||||||
// creates a default one, without the default folder if noDefaultFolder is ture.
|
// creates a default one, without the default folder if noDefaultFolder is ture.
|
||||||
// Otherwise it checks the version, and archives and upgrades the config if
|
// Otherwise it checks the version, and archives and upgrades the config if
|
||||||
// necessary or returns an error, if the version isn't compatible.
|
// necessary or returns an error, if the version isn't compatible.
|
||||||
func LoadConfigAtStartup(path string, cert tls.Certificate, allowNewerConfig, noDefaultFolder bool) (config.Wrapper, error) {
|
func LoadConfigAtStartup(path string, cert tls.Certificate, evLogger events.Logger, allowNewerConfig, noDefaultFolder bool) (config.Wrapper, error) {
|
||||||
myID := protocol.NewDeviceID(cert.Certificate[0])
|
myID := protocol.NewDeviceID(cert.Certificate[0])
|
||||||
cfg, err := config.Load(path, myID)
|
cfg, err := config.Load(path, myID, evLogger)
|
||||||
if fs.IsNotExist(err) {
|
if fs.IsNotExist(err) {
|
||||||
cfg, err = DefaultConfig(path, myID, noDefaultFolder)
|
cfg, err = DefaultConfig(path, myID, evLogger, noDefaultFolder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to generate default config")
|
return nil, errors.Wrap(err, "failed to generate default config")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,12 +19,12 @@ import (
|
|||||||
// verbose format to the console using INFO level.
|
// verbose format to the console using INFO level.
|
||||||
type verboseService struct {
|
type verboseService struct {
|
||||||
suture.Service
|
suture.Service
|
||||||
sub *events.Subscription
|
sub events.Subscription
|
||||||
}
|
}
|
||||||
|
|
||||||
func newVerboseService() *verboseService {
|
func newVerboseService(evLogger events.Logger) *verboseService {
|
||||||
s := &verboseService{
|
s := &verboseService{
|
||||||
sub: events.Default.Subscribe(events.AllEvents),
|
sub: evLogger.Subscribe(events.AllEvents),
|
||||||
}
|
}
|
||||||
s.Service = util.AsService(s.serve)
|
s.Service = util.AsService(s.serve)
|
||||||
return s
|
return s
|
||||||
@ -48,7 +48,7 @@ func (s *verboseService) serve(stop chan struct{}) {
|
|||||||
// Stop stops the verbose logging service.
|
// Stop stops the verbose logging service.
|
||||||
func (s *verboseService) Stop() {
|
func (s *verboseService) Stop() {
|
||||||
s.Service.Stop()
|
s.Service.Stop()
|
||||||
events.Default.Unsubscribe(s.sub)
|
s.sub.Unsubscribe()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -125,19 +125,19 @@ func newAggregator(folderCfg config.FolderConfiguration, ctx context.Context) *a
|
|||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
func Aggregate(in <-chan fs.Event, out chan<- []string, folderCfg config.FolderConfiguration, cfg config.Wrapper, ctx context.Context) {
|
func Aggregate(in <-chan fs.Event, out chan<- []string, folderCfg config.FolderConfiguration, cfg config.Wrapper, evLogger events.Logger, ctx context.Context) {
|
||||||
a := newAggregator(folderCfg, ctx)
|
a := newAggregator(folderCfg, ctx)
|
||||||
|
|
||||||
// Necessary for unit tests where the backend is mocked
|
// Necessary for unit tests where the backend is mocked
|
||||||
go a.mainLoop(in, out, cfg)
|
go a.mainLoop(in, out, cfg, evLogger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aggregator) mainLoop(in <-chan fs.Event, out chan<- []string, cfg config.Wrapper) {
|
func (a *aggregator) mainLoop(in <-chan fs.Event, out chan<- []string, cfg config.Wrapper, evLogger events.Logger) {
|
||||||
a.notifyTimer = time.NewTimer(a.notifyDelay)
|
a.notifyTimer = time.NewTimer(a.notifyDelay)
|
||||||
defer a.notifyTimer.Stop()
|
defer a.notifyTimer.Stop()
|
||||||
|
|
||||||
inProgressItemSubscription := events.Default.Subscribe(events.ItemStarted | events.ItemFinished)
|
inProgressItemSubscription := evLogger.Subscribe(events.ItemStarted | events.ItemFinished)
|
||||||
defer events.Default.Unsubscribe(inProgressItemSubscription)
|
defer inProgressItemSubscription.Unsubscribe()
|
||||||
|
|
||||||
cfg.Subscribe(a)
|
cfg.Subscribe(a)
|
||||||
defer cfg.Unsubscribe(a)
|
defer cfg.Unsubscribe(a)
|
||||||
|
|||||||
@ -47,7 +47,7 @@ var (
|
|||||||
}
|
}
|
||||||
defaultCfg = config.Wrap("", config.Configuration{
|
defaultCfg = config.Wrap("", config.Configuration{
|
||||||
Folders: []config.FolderConfiguration{defaultFolderCfg},
|
Folders: []config.FolderConfiguration{defaultFolderCfg},
|
||||||
})
|
}, events.NoopLogger)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Represents possibly multiple (different event types) expected paths from
|
// Represents possibly multiple (different event types) expected paths from
|
||||||
@ -151,14 +151,17 @@ func TestAggregate(t *testing.T) {
|
|||||||
|
|
||||||
// TestInProgress checks that ignoring files currently edited by Syncthing works
|
// TestInProgress checks that ignoring files currently edited by Syncthing works
|
||||||
func TestInProgress(t *testing.T) {
|
func TestInProgress(t *testing.T) {
|
||||||
|
evLogger := events.NewLogger()
|
||||||
|
go evLogger.Serve()
|
||||||
|
defer evLogger.Stop()
|
||||||
testCase := func(c chan<- fs.Event) {
|
testCase := func(c chan<- fs.Event) {
|
||||||
events.Default.Log(events.ItemStarted, map[string]string{
|
evLogger.Log(events.ItemStarted, map[string]string{
|
||||||
"item": "inprogress",
|
"item": "inprogress",
|
||||||
})
|
})
|
||||||
sleepMs(100)
|
sleepMs(100)
|
||||||
c <- fs.Event{Name: "inprogress", Type: fs.NonRemove}
|
c <- fs.Event{Name: "inprogress", Type: fs.NonRemove}
|
||||||
sleepMs(1000)
|
sleepMs(1000)
|
||||||
events.Default.Log(events.ItemFinished, map[string]interface{}{
|
evLogger.Log(events.ItemFinished, map[string]interface{}{
|
||||||
"item": "inprogress",
|
"item": "inprogress",
|
||||||
})
|
})
|
||||||
sleepMs(100)
|
sleepMs(100)
|
||||||
@ -170,7 +173,7 @@ func TestInProgress(t *testing.T) {
|
|||||||
{[][]string{{"notinprogress"}}, 2000, 3500},
|
{[][]string{{"notinprogress"}}, 2000, 3500},
|
||||||
}
|
}
|
||||||
|
|
||||||
testScenario(t, "InProgress", testCase, expectedBatches)
|
testScenario(t, "InProgress", testCase, expectedBatches, evLogger)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestDelay checks that recurring changes to the same path are delayed
|
// TestDelay checks that recurring changes to the same path are delayed
|
||||||
@ -208,7 +211,7 @@ func TestDelay(t *testing.T) {
|
|||||||
{[][]string{{delayed}, {delAfter}}, 3600, 7000},
|
{[][]string{{delayed}, {delAfter}}, 3600, 7000},
|
||||||
}
|
}
|
||||||
|
|
||||||
testScenario(t, "Delay", testCase, expectedBatches)
|
testScenario(t, "Delay", testCase, expectedBatches, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestNoDelay checks that no delay occurs if there are no non-remove events
|
// TestNoDelay checks that no delay occurs if there are no non-remove events
|
||||||
@ -225,7 +228,7 @@ func TestNoDelay(t *testing.T) {
|
|||||||
{[][]string{{mixed}, {del}}, 500, 2000},
|
{[][]string{{mixed}, {del}}, 500, 2000},
|
||||||
}
|
}
|
||||||
|
|
||||||
testScenario(t, "NoDelay", testCase, expectedBatches)
|
testScenario(t, "NoDelay", testCase, expectedBatches, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEventPaths(dir *eventDir, dirPath string, a *aggregator) []string {
|
func getEventPaths(dir *eventDir, dirPath string, a *aggregator) []string {
|
||||||
@ -277,8 +280,13 @@ func compareBatchToExpectedDirect(t *testing.T, batch []string, expectedPaths []
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testScenario(t *testing.T, name string, testCase func(c chan<- fs.Event), expectedBatches []expectedBatch) {
|
func testScenario(t *testing.T, name string, testCase func(c chan<- fs.Event), expectedBatches []expectedBatch, evLogger events.Logger) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
if evLogger == nil {
|
||||||
|
evLogger = events.NoopLogger
|
||||||
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
eventChan := make(chan fs.Event)
|
eventChan := make(chan fs.Event)
|
||||||
watchChan := make(chan []string)
|
watchChan := make(chan []string)
|
||||||
@ -289,7 +297,7 @@ func testScenario(t *testing.T, name string, testCase func(c chan<- fs.Event), e
|
|||||||
a.notifyTimeout = testNotifyTimeout
|
a.notifyTimeout = testNotifyTimeout
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
go a.mainLoop(eventChan, watchChan, defaultCfg)
|
go a.mainLoop(eventChan, watchChan, defaultCfg, evLogger)
|
||||||
|
|
||||||
sleepMs(20)
|
sleepMs(20)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user