github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/synchronization/state.go (about) 1 package synchronization 2 3 import ( 4 "errors" 5 "fmt" 6 ) 7 8 // Description returns a human-readable description of the session status. 9 func (s Status) Description() string { 10 switch s { 11 case Status_Disconnected: 12 return "Disconnected" 13 case Status_HaltedOnRootEmptied: 14 return "Halted due to one-sided root emptying" 15 case Status_HaltedOnRootDeletion: 16 return "Halted due to root deletion" 17 case Status_HaltedOnRootTypeChange: 18 return "Halted due to root type change" 19 case Status_ConnectingAlpha: 20 return "Connecting to alpha" 21 case Status_ConnectingBeta: 22 return "Connecting to beta" 23 case Status_Watching: 24 return "Watching for changes" 25 case Status_Scanning: 26 return "Scanning files" 27 case Status_WaitingForRescan: 28 return "Waiting 5 seconds for rescan" 29 case Status_Reconciling: 30 return "Reconciling changes" 31 case Status_StagingAlpha: 32 return "Staging files on alpha" 33 case Status_StagingBeta: 34 return "Staging files on beta" 35 case Status_Transitioning: 36 return "Applying changes" 37 case Status_Saving: 38 return "Saving archive" 39 default: 40 return "Unknown" 41 } 42 } 43 44 // MarshalText implements encoding.TextMarshaler.MarshalText. 45 func (s Status) MarshalText() ([]byte, error) { 46 var result string 47 switch s { 48 case Status_Disconnected: 49 result = "disconnected" 50 case Status_HaltedOnRootEmptied: 51 result = "halted-on-root-emptied" 52 case Status_HaltedOnRootDeletion: 53 result = "halted-on-root-deletion" 54 case Status_HaltedOnRootTypeChange: 55 result = "halted-on-root-type-change" 56 case Status_ConnectingAlpha: 57 result = "connecting-alpha" 58 case Status_ConnectingBeta: 59 result = "connecting-beta" 60 case Status_Watching: 61 result = "watching" 62 case Status_Scanning: 63 result = "scanning" 64 case Status_WaitingForRescan: 65 result = "waiting-for-rescan" 66 case Status_Reconciling: 67 result = "reconciling" 68 case Status_StagingAlpha: 69 result = "staging-alpha" 70 case Status_StagingBeta: 71 result = "staging-beta" 72 case Status_Transitioning: 73 result = "transitioning" 74 case Status_Saving: 75 result = "saving" 76 default: 77 result = "unknown" 78 } 79 return []byte(result), nil 80 } 81 82 // ensureValid ensures that EndpointState's invariants are respected. 83 func (s *EndpointState) ensureValid() error { 84 // A nil endpoint state is not valid. 85 if s == nil { 86 return errors.New("nil state") 87 } 88 89 // We could perform additional validation based on the session status and 90 // the endpoint connectivity, but it would be prohibitively complex, and all 91 // we're really concerned about here is memory safety and other structural 92 // invariants. 93 94 // Ensure that all scan problems are valid and truncation is sane. 95 for _, p := range s.ScanProblems { 96 if err := p.EnsureValid(); err != nil { 97 return fmt.Errorf("invalid scan problem detected: %w", err) 98 } 99 } 100 if s.ExcludedScanProblems > 0 && len(s.ScanProblems) == 0 { 101 return errors.New("excluded scan problems reported with no scan problems reported") 102 } 103 104 // Ensure that all transition problems are valid and truncation is sane. 105 for _, p := range s.TransitionProblems { 106 if err := p.EnsureValid(); err != nil { 107 return fmt.Errorf("invalid transition problem detected: %w", err) 108 } 109 } 110 if s.ExcludedTransitionProblems > 0 && len(s.TransitionProblems) == 0 { 111 return errors.New("excluded transition problems reported with no transition problems reported") 112 } 113 114 // Ensure that staging progress is valid. 115 if err := s.StagingProgress.EnsureValid(); err != nil { 116 return fmt.Errorf("invalid staging progress: %w", err) 117 } 118 119 // Success. 120 return nil 121 } 122 123 // EnsureValid ensures that State's invariants are respected. 124 func (s *State) EnsureValid() error { 125 // A nil state is not valid. 126 if s == nil { 127 return errors.New("nil state") 128 } 129 130 // We could perform additional validation based on the session status, but 131 // it would be prohibitively complex, and all we're really concerned about 132 // here is memory safety and other structural invariants. 133 134 // Ensure the session is valid. 135 if err := s.Session.EnsureValid(); err != nil { 136 return fmt.Errorf("invalid session: %w", err) 137 } 138 139 // Ensure that all conflicts are valid and truncation is sane. 140 for _, c := range s.Conflicts { 141 if err := c.EnsureValid(); err != nil { 142 return fmt.Errorf("invalid conflict detected: %w", err) 143 } 144 } 145 if s.ExcludedConflicts > 0 && len(s.Conflicts) == 0 { 146 return errors.New("excluded conflicts reported with no conflicts reported") 147 } 148 149 // Ensure that endpoint states are valid. 150 if err := s.AlphaState.ensureValid(); err != nil { 151 return fmt.Errorf("invalid alpha endpoint state: %w", err) 152 } else if err = s.BetaState.ensureValid(); err != nil { 153 return fmt.Errorf("invalid beta endpoint state: %w", err) 154 } 155 156 // Success. 157 return nil 158 }