folderstate.go 2.7 KB

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