git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/client/status/v2.go (about)

     1  package apistatus
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/apemanager"
     7  	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
     8  	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
     9  	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
    10  	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
    11  )
    12  
    13  // StatusV2 defines a variety of Status instances compatible with FrostFS API V2 protocol.
    14  //
    15  // Note: it is not recommended to use this type directly, it is intended for documentation of the library functionality.
    16  type StatusV2 interface {
    17  	Status
    18  
    19  	// ToStatusV2 returns the status as git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status.Status message structure.
    20  	ToStatusV2() *status.Status
    21  }
    22  
    23  // FromStatusV2 converts status.Status message structure to Status instance. Inverse to ToStatusV2 operation.
    24  //
    25  // If result is not nil, it implements StatusV2. This fact should be taken into account only when passing
    26  // the result to the inverse function ToStatusV2, casts are not compatibility-safe.
    27  //
    28  // Below is the mapping of return codes to Status instance types (with a description of parsing details).
    29  // Note: notice if the return type is a pointer.
    30  //
    31  // Successes:
    32  //   - status.OK: *SuccessDefaultV2 (this also includes nil argument).
    33  //
    34  // Common failures:
    35  //   - status.Internal: *ServerInternal;
    36  //   - status.WrongMagicNumber: *WrongMagicNumber;
    37  //   - status.SignatureVerificationFail: *SignatureVerification;
    38  //   - status.NodeUnderMaintenance: *NodeUnderMaintenance;
    39  //   - status.InvalidArgument: *InvalidArgument.
    40  //
    41  // Object failures:
    42  //   - object.StatusLocked: *ObjectLocked;
    43  //   - object.StatusLockNonRegularObject: *LockNonRegularObject;
    44  //   - object.StatusAccessDenied: *ObjectAccessDenied;
    45  //   - object.StatusNotFound: *ObjectNotFound;
    46  //   - object.StatusAlreadyRemoved: *ObjectAlreadyRemoved;
    47  //   - object.StatusOutOfRange: *ObjectOutOfRange.
    48  //
    49  // Container failures:
    50  //   - container.StatusNotFound: *ContainerNotFound;
    51  //   - container.StatusEACLNotFound: *EACLNotFound.
    52  //
    53  // Session failures:
    54  //   - session.StatusTokenNotFound: *SessionTokenNotFound;
    55  //   - session.StatusTokenExpired: *SessionTokenExpired.
    56  //
    57  // APE Manager failures
    58  //   - apemanager.StatusAPEManagerAccessDenied: *APEManagerAccessDenied.
    59  func FromStatusV2(st *status.Status) Status {
    60  	var decoder interface {
    61  		fromStatusV2(*status.Status)
    62  	}
    63  
    64  	switch code := st.Code(); {
    65  	case status.IsSuccess(code):
    66  		//nolint:exhaustive
    67  		switch status.LocalizeSuccess(&code); code {
    68  		case status.OK:
    69  			decoder = new(SuccessDefaultV2)
    70  		}
    71  	case status.IsCommonFail(code):
    72  		switch status.LocalizeCommonFail(&code); code {
    73  		case status.Internal:
    74  			decoder = new(ServerInternal)
    75  		case status.WrongMagicNumber:
    76  			decoder = new(WrongMagicNumber)
    77  		case status.SignatureVerificationFail:
    78  			decoder = new(SignatureVerification)
    79  		case status.NodeUnderMaintenance:
    80  			decoder = new(NodeUnderMaintenance)
    81  		case status.InvalidArgument:
    82  			decoder = new(InvalidArgument)
    83  		}
    84  	case object.LocalizeFailStatus(&code):
    85  		switch code {
    86  		case object.StatusLocked:
    87  			decoder = new(ObjectLocked)
    88  		case object.StatusLockNonRegularObject:
    89  			decoder = new(LockNonRegularObject)
    90  		case object.StatusAccessDenied:
    91  			decoder = new(ObjectAccessDenied)
    92  		case object.StatusNotFound:
    93  			decoder = new(ObjectNotFound)
    94  		case object.StatusAlreadyRemoved:
    95  			decoder = new(ObjectAlreadyRemoved)
    96  		case object.StatusOutOfRange:
    97  			decoder = new(ObjectOutOfRange)
    98  		}
    99  	case container.LocalizeFailStatus(&code):
   100  		//nolint:exhaustive
   101  		switch code {
   102  		case container.StatusNotFound:
   103  			decoder = new(ContainerNotFound)
   104  		case container.StatusEACLNotFound:
   105  			decoder = new(EACLNotFound)
   106  		}
   107  	case session.LocalizeFailStatus(&code):
   108  		//nolint:exhaustive
   109  		switch code {
   110  		case session.StatusTokenNotFound:
   111  			decoder = new(SessionTokenNotFound)
   112  		case session.StatusTokenExpired:
   113  			decoder = new(SessionTokenExpired)
   114  		}
   115  	case apemanager.LocalizeFailStatus(&code):
   116  		//nolint:exhaustive
   117  		switch code {
   118  		case apemanager.StatusAPEManagerAccessDenied:
   119  			decoder = new(APEManagerAccessDenied)
   120  		}
   121  	}
   122  
   123  	if decoder == nil {
   124  		decoder = new(unrecognizedStatusV2)
   125  	}
   126  
   127  	decoder.fromStatusV2(st)
   128  
   129  	return decoder
   130  }
   131  
   132  // ToStatusV2 converts Status instance to status.Status message structure. Inverse to FromStatusV2 operation.
   133  //
   134  // If argument is the StatusV2 instance, it is converted directly.
   135  // Otherwise, successes are converted with status.OK code w/o details and message,
   136  // failures - with status.Internal and error text message w/o details.
   137  func ToStatusV2(st Status) *status.Status {
   138  	if v, ok := st.(StatusV2); ok {
   139  		return v.ToStatusV2()
   140  	}
   141  
   142  	if IsSuccessful(st) {
   143  		return newStatusV2WithLocalCode(status.OK, status.GlobalizeSuccess)
   144  	}
   145  
   146  	internalErrorStatus := newStatusV2WithLocalCode(status.Internal, status.GlobalizeCommonFail)
   147  	internalErrorStatus.SetMessage(st.(error).Error()) // type cast never panics because IsSuccessful() checks cast
   148  
   149  	return internalErrorStatus
   150  }
   151  
   152  func errMessageStatusV2(code any, msg string) string {
   153  	const (
   154  		noMsgFmt = "status: code = %v"
   155  		msgFmt   = noMsgFmt + " message = %s"
   156  	)
   157  
   158  	if msg != "" {
   159  		return fmt.Sprintf(msgFmt, code, msg)
   160  	}
   161  
   162  	return fmt.Sprintf(noMsgFmt, code)
   163  }
   164  
   165  func newStatusV2WithLocalCode(code status.Code, globalizer func(*status.Code)) *status.Status {
   166  	var st status.Status
   167  
   168  	st.SetCode(globalizeCodeV2(code, globalizer))
   169  
   170  	return &st
   171  }
   172  
   173  func globalizeCodeV2(code status.Code, globalizer func(*status.Code)) status.Code {
   174  	globalizer(&code)
   175  	return code
   176  }