File: folderstate.go

package info (click to toggle)
syncthing 1.0.0~ds1-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 11,096 kB
  • sloc: xml: 1,028; sh: 219; makefile: 61
file content (128 lines) | stat: -rw-r--r-- 2,753 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Copyright (C) 2015 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

package model

import (
	"time"

	"github.com/syncthing/syncthing/lib/events"
	"github.com/syncthing/syncthing/lib/sync"
)

type folderState int

const (
	FolderIdle folderState = iota
	FolderScanning
	FolderScanWaiting
	FolderSyncing
	FolderError
)

func (s folderState) String() string {
	switch s {
	case FolderIdle:
		return "idle"
	case FolderScanning:
		return "scanning"
	case FolderScanWaiting:
		return "scan-waiting"
	case FolderSyncing:
		return "syncing"
	case FolderError:
		return "error"
	default:
		return "unknown"
	}
}

type stateTracker struct {
	folderID string

	mut     sync.Mutex
	current folderState
	err     error
	changed time.Time
}

func newStateTracker(id string) stateTracker {
	return stateTracker{
		folderID: id,
		mut:      sync.NewMutex(),
	}
}

// setState sets the new folder state, for states other than FolderError.
func (s *stateTracker) setState(newState folderState) {
	if newState == FolderError {
		panic("must use setError")
	}

	s.mut.Lock()
	if newState != s.current {
		/* This should hold later...
		if s.current != FolderIdle && (newState == FolderScanning || newState == FolderSyncing) {
			panic("illegal state transition " + s.current.String() + " -> " + newState.String())
		}
		*/

		eventData := map[string]interface{}{
			"folder": s.folderID,
			"to":     newState.String(),
			"from":   s.current.String(),
		}

		if !s.changed.IsZero() {
			eventData["duration"] = time.Since(s.changed).Seconds()
		}

		s.current = newState
		s.changed = time.Now()

		events.Default.Log(events.StateChanged, eventData)
	}
	s.mut.Unlock()
}

// getState returns the current state, the time when it last changed, and the
// current error or nil.
func (s *stateTracker) getState() (current folderState, changed time.Time, err error) {
	s.mut.Lock()
	current, changed, err = s.current, s.changed, s.err
	s.mut.Unlock()
	return
}

// setError sets the folder state to FolderError with the specified error or
// to FolderIdle if the error is nil
func (s *stateTracker) setError(err error) {
	s.mut.Lock()
	defer s.mut.Unlock()

	eventData := map[string]interface{}{
		"folder": s.folderID,
		"from":   s.current.String(),
	}

	if err != nil {
		eventData["error"] = err.Error()
		s.current = FolderError
	} else {
		s.current = FolderIdle
	}

	eventData["to"] = s.current.String()

	if !s.changed.IsZero() {
		eventData["duration"] = time.Since(s.changed).Seconds()
	}

	s.err = err
	s.changed = time.Now()

	events.Default.Log(events.StateChanged, eventData)
}