1
0
Fork 0
mirror of https://github.com/Luzifer/cloudbox.git synced 2024-11-08 14:10:09 +00:00
cloudbox/sync/state.go

156 lines
2.8 KiB
Go

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
}
func (c Change) HasAll(test ...Change) bool {
for _, t := range test {
if c&t == 0 {
return false
}
}
return true
}
func (c Change) HasOne(test ...Change) bool {
for _, t := range test {
if c&t != 0 {
return true
}
}
return false
}
func (c Change) Is(test Change) bool {
return c == test
}
const (
sideLocal string = "local"
sideRemote string = "remote"
sourceDB string = "db"
sourceScan string = "scan"
)
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
}
func (s *state) Set(side, source string, info providers.FileInfo) {
s.lock.Lock()
defer s.lock.Unlock()
if _, ok := s.files[info.RelativeName]; !ok {
s.files[info.RelativeName] = &stateDetail{}
}
switch strings.Join([]string{side, source}, "::") {
case "local::db":
s.files[info.RelativeName].LocalDB = &info
case "local::scan":
s.files[info.RelativeName].LocalScan = &info
case "remote::db":
s.files[info.RelativeName].RemoteDB = &info
case "remote::scan":
s.files[info.RelativeName].RemoteScan = &info
}
}