EdgexAgent/device-ble-go/vendor/github.com/parallaxsecond/parsec-client-go/interface/requests/response.go
2025-07-10 20:40:32 +08:00

207 lines
9.9 KiB
Go

// Copyright 2021 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
package requests
import (
"bytes"
"reflect"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"
)
const wireHeaderSizeValue uint16 = 30
const WireHeaderSize uint16 = wireHeaderSizeValue + 6
// StatusCode type to represent status codes in response headers
type StatusCode uint16
// StatusCode values for response status codes defined here: https://parallaxsecond.github.io/parsec-book/parsec_client/status_codes.html.
const (
// Service Internal Response Status Codes
StatusSuccess StatusCode = 0 // Operation was a success
StatusWrongProviderID StatusCode = 1 // Requested provider ID does not match that of the backend
StatusContentTypeNotSupported StatusCode = 2 // Requested content type is not supported by the backend
StatusAcceptTypeNotSupported StatusCode = 3 // Requested accept type is not supported by the backend
StatusWireProtocolVersionNotSupported StatusCode = 4 // Requested version is not supported by the backend
StatusProviderNotRegistered StatusCode = 5 // No provider registered for the requested provider ID
StatusProviderDoesNotExist StatusCode = 6 // No provider defined for requested provider ID
StatusDeserializingBodyFailed StatusCode = 7 // Failed to deserialize the body of the message
StatusSerializingBodyFailed StatusCode = 8 // Failed to serialize the body of the message
StatusOpcodeDoesNotExist StatusCode = 9 // Requested operation is not defined
StatusResponseTooLarge StatusCode = 10 // Response size exceeds allowed limits
StatusAuthenticationError StatusCode = 11 // Authentication failed
StatusAuthenticatorDoesNotExist StatusCode = 12 // Authenticator not supported
StatusAuthenticatorNotRegistered StatusCode = 13 // Authenticator not supported
StatusKeyInfoManagerError StatusCode = 14 // Internal error in the Key Info Manager
StatusConnectionError StatusCode = 15 // Generic input/output error
StatusInvalidEncoding StatusCode = 16 // Invalid value for this data type
StatusInvalidHeader StatusCode = 17 // Constant fields in header are invalid
StatusWrongProviderUUID StatusCode = 18 // The UUID vector needs to only contain 16 bytes
StatusNotAuthenticated StatusCode = 19 // Request did not provide a required authentication
StatusBodySizeExceedsLimit StatusCode = 20 // Request length specified in the header is above defined limit
StatusAdminOperation StatusCode = 21 // The operation requires admin privilege
// PSA Response Status Codes
StatusPsaErrorGenericError StatusCode = 1132 // An error occurred that does not correspond to any defined failure cause
StatusPsaErrorNotPermitted StatusCode = 1133 // The requested action is denied by a policy
StatusPsaErrorNotSupported StatusCode = 1134 // The requested operation or a parameter is not supported by this implementation
StatusPsaErrorInvalidArgument StatusCode = 1135 // The parameters passed to the function are invalid
StatusPsaErrorInvalidHandle StatusCode = 1136 // The key handle is not valid
StatusPsaErrorBadState StatusCode = 1137 // The requested action cannot be performed in the current state
StatusPsaErrorBufferTooSmall StatusCode = 1138 // An output buffer is too small
StatusPsaErrorAlreadyExists StatusCode = 1139 // Asking for an item that already exists
StatusPsaErrorDoesNotExist StatusCode = 1140 // Asking for an item that doesn't exist
StatusPsaErrorInsufficientMemory StatusCode = 1141 // There is not enough runtime memory
StatusPsaErrorInsufficientStorage StatusCode = 1142 // There is not enough persistent storage available
StatusPsaErrorInssuficientData StatusCode = 1143 // Insufficient data when attempting to read from a resource
StatusPsaErrorCommunicationFailure StatusCode = 1145 // There was a communication failure inside the implementation
StatusPsaErrorStorageFailure StatusCode = 1146 // There was a storage failure that may have led to data loss
StatusPsaErrorHardwareFailure StatusCode = 1147 // A hardware failure was detected
StatusPsaErrorInsufficientEntropy StatusCode = 1148 // There is not enough entropy to generate random data needed for the requested action
StatusPsaErrorInvalidSignature StatusCode = 1149 // The signature, MAC or hash is incorrect
StatusPsaErrorInvalidPadding StatusCode = 1150 // The decrypted padding is incorrect
StatusPsaErrorCorruptionDetected StatusCode = 1151 // A tampering attempt was detected
StatusPsaErrorDataCorrupt StatusCode = 1152 // Stored data has been corrupted
)
func (code StatusCode) IsValid() bool {
return (code >= StatusSuccess && code <= StatusAdminOperation) || (code >= StatusPsaErrorGenericError && code <= StatusPsaErrorDataCorrupt)
}
// ParseResponse returns a response if it successfully unmarshals the given byte buffer
func ParseResponse(expectedOpCode OpCode, buf *bytes.Buffer, responseProtoBuf proto.Message) error {
if buf == nil {
return errors.Errorf("nil buffer supplied")
}
if responseProtoBuf == nil || reflect.ValueOf(responseProtoBuf).IsNil() {
return errors.Errorf("nil message supplied")
}
hdrBuf := make([]byte, WireHeaderSize)
_, err := buf.Read(hdrBuf)
if err != nil {
return errors.Wrap(err, "failed to read header")
}
wireHeader, err := parseWireHeaderFromBuf(bytes.NewBuffer(hdrBuf))
if err != nil {
return errors.Wrap(err, "failed to parse header")
}
if wireHeader.opCode != expectedOpCode {
// If we've not got the opcode we expect, don't even try to deserialise the body.
return errors.Errorf("was expecting response with op code %v, got %v", expectedOpCode, wireHeader.opCode)
}
bodyBuf := make([]byte, wireHeader.bodyLen)
n, err := buf.Read(bodyBuf)
if err != nil {
return errors.Wrap(err, "failed to read body")
}
if uint32(n) != wireHeader.bodyLen {
return errors.Errorf("body underflow error, expected %v bytes, got %v", wireHeader.bodyLen, n)
}
err = proto.Unmarshal(bodyBuf, responseProtoBuf)
if err != nil {
return err
}
return wireHeader.Status.ToErr()
}
// ToErr returns nil if the response code is a success, or an appropriate error otherwise.
//
//nolint:gocyclo
func (code StatusCode) ToErr() error {
switch code {
case StatusSuccess:
return nil
case StatusWrongProviderID:
return errors.Errorf("wrong provider id")
case StatusContentTypeNotSupported:
return errors.Errorf("content type not supported")
case StatusAcceptTypeNotSupported:
return errors.Errorf("accept type not supported")
case StatusWireProtocolVersionNotSupported:
return errors.Errorf("requested version is not supported by the backend")
case StatusProviderNotRegistered:
return errors.Errorf("provider not registered")
case StatusProviderDoesNotExist:
return errors.Errorf("provider does not exist")
case StatusDeserializingBodyFailed:
return errors.Errorf("deserializing body failed")
case StatusSerializingBodyFailed:
return errors.Errorf("serializing body failed")
case StatusOpcodeDoesNotExist:
return errors.Errorf("opcode does not exist")
case StatusResponseTooLarge:
return errors.Errorf("response too large")
case StatusAuthenticationError:
return errors.Errorf("authentication error")
case StatusAuthenticatorDoesNotExist:
return errors.Errorf("authentication does not exist")
case StatusAuthenticatorNotRegistered:
return errors.Errorf("authentication not registered")
case StatusKeyInfoManagerError:
return errors.Errorf("internal error in the Key Info Manager")
case StatusConnectionError:
return errors.Errorf("generic input/output error")
case StatusInvalidEncoding:
return errors.Errorf("invalid value for this data type")
case StatusInvalidHeader:
return errors.Errorf("constant fields in header are invalid")
case StatusWrongProviderUUID:
return errors.Errorf("the UUID vector needs to only contain 16 bytes")
case StatusNotAuthenticated:
return errors.Errorf("request did not provide a required authentication")
case StatusBodySizeExceedsLimit:
return errors.Errorf("request length specified in the header is above defined limit")
case StatusAdminOperation:
return errors.Errorf("the operation requires admin privilege")
case StatusPsaErrorGenericError:
return errors.Errorf("generic error")
case StatusPsaErrorNotPermitted:
return errors.Errorf("not permitted")
case StatusPsaErrorNotSupported:
return errors.Errorf("not supported")
case StatusPsaErrorInvalidArgument:
return errors.Errorf("invalid argument")
case StatusPsaErrorInvalidHandle:
return errors.Errorf("invalid handle")
case StatusPsaErrorBadState:
return errors.Errorf("bad state")
case StatusPsaErrorBufferTooSmall:
return errors.Errorf("buffer too small")
case StatusPsaErrorAlreadyExists:
return errors.Errorf("already exists")
case StatusPsaErrorDoesNotExist:
return errors.Errorf("does not exist")
case StatusPsaErrorInsufficientMemory:
return errors.Errorf("insufficient memory")
case StatusPsaErrorInsufficientStorage:
return errors.Errorf("insufficient storage")
case StatusPsaErrorInssuficientData:
return errors.Errorf("insufficient data")
case StatusPsaErrorCommunicationFailure:
return errors.Errorf("communications failure")
case StatusPsaErrorStorageFailure:
return errors.Errorf("storage failure")
case StatusPsaErrorHardwareFailure:
return errors.Errorf("hardware failure")
case StatusPsaErrorInsufficientEntropy:
return errors.Errorf("insufficient entropy")
case StatusPsaErrorInvalidSignature:
return errors.Errorf("invalid signature")
case StatusPsaErrorInvalidPadding:
return errors.Errorf("invalid padding")
case StatusPsaErrorCorruptionDetected:
return errors.Errorf("tampering detected")
case StatusPsaErrorDataCorrupt:
return errors.Errorf("stored data has been corrupted")
}
return errors.Errorf("unknown error code")
}