folderstate.go 3.1 KB

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