go-gun/gun/state.go

80 lines
3.2 KiB
Go
Raw Normal View History

2019-02-20 20:54:46 +00:00
package gun
import (
"bytes"
"encoding/json"
2019-02-20 20:54:46 +00:00
"time"
)
2019-02-26 21:59:44 +00:00
// State represents the conflict state of this value. It is usually the Unix
// time in milliseconds.
type State float64 // TODO: what if larger?
2019-02-25 05:14:26 +00:00
2019-02-26 21:59:44 +00:00
// StateNow is the current machine state (i.e. current Unix time in ms).
func StateNow() State {
// TODO: Should I use timeNowUniqueUnix or otherwise set decimal spots to disambiguate?
return State(timeNowUnixMs())
}
2019-02-25 05:14:26 +00:00
2019-02-26 21:59:44 +00:00
// StateFromTime converts a time to a State (i.e. converts to Unix ms).
func StateFromTime(t time.Time) State { return State(timeToUnixMs(t)) }
2019-02-20 20:54:46 +00:00
2019-02-26 21:59:44 +00:00
// ConflictResolution is how to handle two values for the same field.
type ConflictResolution int
const (
2019-02-26 21:59:44 +00:00
// ConflictResolutionNeverSeenUpdate occurs when there is no existing value.
// It means an update should always occur.
ConflictResolutionNeverSeenUpdate ConflictResolution = iota
2019-02-26 21:59:44 +00:00
// ConflictResolutionTooFutureDeferred occurs when the update is after our
// current machine state. It means the update should be deferred.
ConflictResolutionTooFutureDeferred
2019-02-26 21:59:44 +00:00
// ConflictResolutionOlderHistorical occurs when the update happened before
// the existing value's last update. It means it can be noted, but the
// update should be discarded.
ConflictResolutionOlderHistorical
2019-02-26 21:59:44 +00:00
// ConflictResolutionNewerUpdate occurs when the update happened after last
// update but is not beyond ur current machine state. It means the update
// should overwrite.
ConflictResolutionNewerUpdate
2019-02-26 21:59:44 +00:00
// ConflictResolutionSameKeep occurs when the update happened at the same
// time and it is lexically not the one chosen. It means the update should
// be discarded.
ConflictResolutionSameKeep
2019-02-26 21:59:44 +00:00
// ConflictResolutionSameUpdate occurs when the update happened at the same
// time and it is lexically the one chosen. It means the update should
// overwrite.
ConflictResolutionSameUpdate
)
2019-02-20 20:54:46 +00:00
2019-02-26 21:59:44 +00:00
// IsImmediateUpdate returns true for ConflictResolutionNeverSeenUpdate,
// ConflictResolutionNewerUpdate, and ConflictResolutionSameUpdate
func (c ConflictResolution) IsImmediateUpdate() bool {
return c == ConflictResolutionNeverSeenUpdate || c == ConflictResolutionNewerUpdate || c == ConflictResolutionSameUpdate
2019-02-20 20:54:46 +00:00
}
2019-02-26 21:59:44 +00:00
// ConflictResolve checks the existing val/state, new val/state, and the current
// machine state to choose what to do with the update. Note, the existing val
// should always exist meaning it will never return
// ConflictResolutionNeverSeenUpdate.
func ConflictResolve(existingVal Value, existingState State, newVal Value, newState State, sysState State) ConflictResolution {
// Existing gunjs impl serializes to JSON first to do lexical comparisons, so we will too
if sysState < newState {
return ConflictResolutionTooFutureDeferred
} else if newState < existingState {
return ConflictResolutionOlderHistorical
} else if existingState < newState {
return ConflictResolutionNewerUpdate
} else if existingVal == newVal {
return ConflictResolutionSameKeep
} else if existingJSON, err := json.Marshal(existingVal); err != nil {
panic(err)
} else if newJSON, err := json.Marshal(newVal); err != nil {
panic(err)
} else if bytes.Compare(existingJSON, newJSON) < 0 {
return ConflictResolutionSameUpdate
} else {
return ConflictResolutionSameKeep
2019-02-20 20:54:46 +00:00
}
}