folder.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package model
  7. import (
  8. "context"
  9. "time"
  10. "github.com/syncthing/syncthing/lib/config"
  11. "github.com/syncthing/syncthing/lib/watchaggregator"
  12. )
  13. type folder struct {
  14. stateTracker
  15. config.FolderConfiguration
  16. scan folderScanner
  17. model *Model
  18. ctx context.Context
  19. cancel context.CancelFunc
  20. initialScanFinished chan struct{}
  21. watchCancel context.CancelFunc
  22. watchChan chan []string
  23. ignoresUpdated chan struct{} // The ignores changed, we need to restart watcher
  24. }
  25. func newFolder(model *Model, cfg config.FolderConfiguration) folder {
  26. ctx, cancel := context.WithCancel(context.Background())
  27. return folder{
  28. stateTracker: newStateTracker(cfg.ID),
  29. FolderConfiguration: cfg,
  30. scan: newFolderScanner(cfg),
  31. ctx: ctx,
  32. cancel: cancel,
  33. model: model,
  34. initialScanFinished: make(chan struct{}),
  35. }
  36. }
  37. func (f *folder) IndexUpdated() {
  38. }
  39. func (f *folder) DelayScan(next time.Duration) {
  40. f.scan.Delay(next)
  41. }
  42. func (f *folder) Scan(subdirs []string) error {
  43. <-f.initialScanFinished
  44. return f.scan.Scan(subdirs)
  45. }
  46. func (f *folder) Stop() {
  47. f.cancel()
  48. }
  49. func (f *folder) Jobs() ([]string, []string) {
  50. return nil, nil
  51. }
  52. func (f *folder) BringToFront(string) {}
  53. func (f *folder) BlockStats() map[string]int {
  54. return nil
  55. }
  56. func (f *folder) scanSubdirs(subDirs []string) error {
  57. if err := f.model.internalScanFolderSubdirs(f.ctx, f.folderID, subDirs); err != nil {
  58. // Potentially sets the error twice, once in the scanner just
  59. // by doing a check, and once here, if the error returned is
  60. // the same one as returned by CheckFolderHealth, though
  61. // duplicate set is handled by setError.
  62. f.setError(err)
  63. return err
  64. }
  65. return nil
  66. }
  67. func (f *folder) scanTimerFired() {
  68. err := f.scanSubdirs(nil)
  69. select {
  70. case <-f.initialScanFinished:
  71. default:
  72. status := "Completed"
  73. if err != nil {
  74. status = "Failed"
  75. }
  76. l.Infoln(status, "initial scan of", f.Type.String(), "folder", f.Description())
  77. close(f.initialScanFinished)
  78. }
  79. f.scan.Reschedule()
  80. }
  81. func (f *folder) startWatcher() {
  82. ctx, cancel := context.WithCancel(f.ctx)
  83. f.model.fmut.RLock()
  84. ignores := f.model.folderIgnores[f.folderID]
  85. f.model.fmut.RUnlock()
  86. eventChan, err := f.Filesystem().Watch(".", ignores, ctx, f.IgnorePerms)
  87. if err != nil {
  88. l.Warnf("Failed to start filesystem watcher for folder %s: %v", f.Description(), err)
  89. } else {
  90. f.watchChan = make(chan []string)
  91. f.watchCancel = cancel
  92. watchaggregator.Aggregate(eventChan, f.watchChan, f.FolderConfiguration, f.model.cfg, ctx)
  93. l.Infoln("Started filesystem watcher for folder", f.Description())
  94. }
  95. }
  96. func (f *folder) restartWatcher() {
  97. f.watchCancel()
  98. f.startWatcher()
  99. f.Scan(nil)
  100. }
  101. func (f *folder) IgnoresUpdated() {
  102. select {
  103. case f.ignoresUpdated <- struct{}{}:
  104. default:
  105. // We might be busy doing a pull and thus not reading from this
  106. // channel. The channel is 1-buffered, so one notification will be
  107. // queued to ensure we recheck after the pull.
  108. }
  109. }