2019-06-16 16:53:30 +00:00
|
|
|
package sync
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/Luzifer/cloudbox/providers"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Change uint8
|
|
|
|
|
|
|
|
const (
|
|
|
|
ChangeLocalAdd Change = 1 << iota
|
|
|
|
ChangeLocalDelete
|
|
|
|
ChangeLocalUpdate
|
|
|
|
ChangeRemoteAdd
|
|
|
|
ChangeRemoteDelete
|
|
|
|
ChangeRemoteUpdate
|
|
|
|
)
|
|
|
|
|
|
|
|
func (c Change) Changed() bool {
|
|
|
|
return c != 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Change) Register(add Change) {
|
|
|
|
*c = *c | add
|
|
|
|
}
|
|
|
|
|
2019-06-16 20:42:42 +00:00
|
|
|
func (c Change) HasAll(test ...Change) bool {
|
|
|
|
for _, t := range test {
|
|
|
|
if c&t == 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2019-06-16 17:57:02 +00:00
|
|
|
func (c Change) HasOne(test ...Change) bool {
|
|
|
|
for _, t := range test {
|
|
|
|
if c&t != 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
2019-06-16 16:53:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c Change) Is(test Change) bool {
|
|
|
|
return c == test
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
2019-06-16 17:57:02 +00:00
|
|
|
sideLocal string = "local"
|
|
|
|
sideRemote string = "remote"
|
|
|
|
sourceDB string = "db"
|
|
|
|
sourceScan string = "scan"
|
2019-06-16 16:53:30 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type stateDetail struct {
|
|
|
|
LocalDB,
|
|
|
|
LocalScan,
|
|
|
|
RemoteDB,
|
|
|
|
RemoteScan *providers.FileInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
type state struct {
|
|
|
|
files map[string]*stateDetail
|
|
|
|
lock sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func newState() *state {
|
|
|
|
return &state{
|
|
|
|
files: make(map[string]*stateDetail),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *state) GetChangeFor(relativeName string) (result Change) {
|
|
|
|
s.lock.Lock()
|
|
|
|
defer s.lock.Unlock()
|
|
|
|
|
|
|
|
d := s.files[relativeName]
|
|
|
|
|
|
|
|
// No changes detected
|
|
|
|
if d.LocalDB.Equal(d.LocalScan) && d.RemoteDB.Equal(d.RemoteScan) {
|
|
|
|
// Check special case: Something went really wrong and sync state is FUBAR
|
|
|
|
if d.LocalDB == nil && d.RemoteDB != nil {
|
|
|
|
result.Register(ChangeRemoteAdd)
|
|
|
|
}
|
|
|
|
if d.LocalDB != nil && d.RemoteDB == nil {
|
|
|
|
result.Register(ChangeLocalAdd)
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for local changes
|
|
|
|
switch {
|
|
|
|
case d.LocalDB == nil && d.LocalScan != nil:
|
|
|
|
result.Register(ChangeLocalAdd)
|
|
|
|
|
|
|
|
case d.LocalDB != nil && d.LocalScan == nil:
|
|
|
|
result.Register(ChangeLocalDelete)
|
|
|
|
|
|
|
|
case !d.LocalDB.Equal(d.LocalScan):
|
|
|
|
result.Register(ChangeLocalUpdate)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for remote changes
|
|
|
|
switch {
|
|
|
|
case d.RemoteDB == nil && d.RemoteScan != nil:
|
|
|
|
result.Register(ChangeRemoteAdd)
|
|
|
|
|
|
|
|
case d.RemoteDB != nil && d.RemoteScan == nil:
|
|
|
|
result.Register(ChangeRemoteDelete)
|
|
|
|
|
|
|
|
case !d.RemoteDB.Equal(d.RemoteScan):
|
|
|
|
result.Register(ChangeRemoteUpdate)
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *state) GetRelativeNames() []string {
|
|
|
|
s.lock.Lock()
|
|
|
|
defer s.lock.Unlock()
|
|
|
|
|
|
|
|
out := []string{}
|
|
|
|
for k := range s.files {
|
|
|
|
out = append(out, k)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Strings(out)
|
|
|
|
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2019-06-16 17:57:02 +00:00
|
|
|
func (s *state) Set(side, source string, info providers.FileInfo) {
|
2019-06-16 16:53:30 +00:00
|
|
|
s.lock.Lock()
|
|
|
|
defer s.lock.Unlock()
|
|
|
|
|
2019-06-16 17:57:02 +00:00
|
|
|
if _, ok := s.files[info.RelativeName]; !ok {
|
|
|
|
s.files[info.RelativeName] = &stateDetail{}
|
2019-06-16 16:53:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch strings.Join([]string{side, source}, "::") {
|
|
|
|
case "local::db":
|
2019-06-16 17:57:02 +00:00
|
|
|
s.files[info.RelativeName].LocalDB = &info
|
2019-06-16 16:53:30 +00:00
|
|
|
case "local::scan":
|
2019-06-16 17:57:02 +00:00
|
|
|
s.files[info.RelativeName].LocalScan = &info
|
2019-06-16 16:53:30 +00:00
|
|
|
case "remote::db":
|
2019-06-16 17:57:02 +00:00
|
|
|
s.files[info.RelativeName].RemoteDB = &info
|
2019-06-16 16:53:30 +00:00
|
|
|
case "remote::scan":
|
2019-06-16 17:57:02 +00:00
|
|
|
s.files[info.RelativeName].RemoteScan = &info
|
2019-06-16 16:53:30 +00:00
|
|
|
}
|
|
|
|
}
|