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  }