folderstate.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // Copyright (C) 2015 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. "time"
  9. "github.com/syncthing/syncthing/lib/events"
  10. "github.com/syncthing/syncthing/lib/sync"
  11. )
  12. type folderState int
  13. const (
  14. FolderIdle folderState = iota
  15. FolderScanning
  16. FolderScanWaiting
  17. FolderSyncPreparing
  18. FolderSyncing
  19. FolderError
  20. )
  21. func (s folderState) String() string {
  22. switch s {
  23. case FolderIdle:
  24. return "idle"
  25. case FolderScanning:
  26. return "scanning"
  27. case FolderScanWaiting:
  28. return "scan-waiting"
  29. case FolderSyncPreparing:
  30. return "sync-preparing"
  31. case FolderSyncing:
  32. return "syncing"
  33. case FolderError:
  34. return "error"
  35. default:
  36. return "unknown"
  37. }
  38. }
  39. type stateTracker struct {
  40. folderID string
  41. evLogger events.Logger
  42. mut sync.Mutex
  43. current folderState
  44. err error
  45. changed time.Time
  46. }
  47. func newStateTracker(id string, evLogger events.Logger) stateTracker {
  48. return stateTracker{
  49. folderID: id,
  50. evLogger: evLogger,
  51. mut: sync.NewMutex(),
  52. }
  53. }
  54. // setState sets the new folder state, for states other than FolderError.
  55. func (s *stateTracker) setState(newState folderState) {
  56. if newState == FolderError {
  57. panic("must use setError")
  58. }
  59. s.mut.Lock()
  60. defer s.mut.Unlock()
  61. if newState == s.current {
  62. return
  63. }
  64. /* This should hold later...
  65. if s.current != FolderIdle && (newState == FolderScanning || newState == FolderSyncing) {
  66. panic("illegal state transition " + s.current.String() + " -> " + newState.String())
  67. }
  68. */
  69. eventData := map[string]interface{}{
  70. "folder": s.folderID,
  71. "to": newState.String(),
  72. "from": s.current.String(),
  73. }
  74. if !s.changed.IsZero() {
  75. eventData["duration"] = time.Since(s.changed).Seconds()
  76. }
  77. s.current = newState
  78. s.changed = time.Now()
  79. s.evLogger.Log(events.StateChanged, eventData)
  80. }
  81. // getState returns the current state, the time when it last changed, and the
  82. // current error or nil.
  83. func (s *stateTracker) getState() (current folderState, changed time.Time, err error) {
  84. s.mut.Lock()
  85. current, changed, err = s.current, s.changed, s.err
  86. s.mut.Unlock()
  87. return
  88. }
  89. // setError sets the folder state to FolderError with the specified error or
  90. // to FolderIdle if the error is nil
  91. func (s *stateTracker) setError(err error) {
  92. s.mut.Lock()
  93. defer s.mut.Unlock()
  94. eventData := map[string]interface{}{
  95. "folder": s.folderID,
  96. "from": s.current.String(),
  97. }
  98. if err != nil {
  99. eventData["error"] = err.Error()
  100. s.current = FolderError
  101. } else {
  102. s.current = FolderIdle
  103. }
  104. eventData["to"] = s.current.String()
  105. if !s.changed.IsZero() {
  106. eventData["duration"] = time.Since(s.changed).Seconds()
  107. }
  108. s.err = err
  109. s.changed = time.Now()
  110. s.evLogger.Log(events.StateChanged, eventData)
  111. }