feat: add command domain invariants
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unicode/utf8"
|
||||
|
||||
rvboxv1 "github.com/rvbox/rvbox/gen/go/rvbox/v1"
|
||||
)
|
||||
|
||||
const MaxProtocolDetailBytes = 4 * 1024
|
||||
|
||||
// Error is the transport-neutral form of an RVBox structured failure.
|
||||
type Error struct {
|
||||
Code rvboxv1.ControlError_Code
|
||||
Message string
|
||||
Retryable bool
|
||||
IssueUUID string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
if e.IssueUUID == "" {
|
||||
return fmt.Sprintf("%s: %s", e.Code, e.Message)
|
||||
}
|
||||
return fmt.Sprintf("%s (%s): %s", e.Code, e.IssueUUID, e.Message)
|
||||
}
|
||||
|
||||
func (e *Error) Unwrap() error { return e.Cause }
|
||||
|
||||
// NewError applies the stable retryability policy and bounds wire-visible text.
|
||||
func NewError(code rvboxv1.ControlError_Code, message, issueUUID string) *Error {
|
||||
return &Error{
|
||||
Code: code,
|
||||
Message: boundUTF8(message, MaxProtocolDetailBytes),
|
||||
Retryable: DefaultRetryable(code),
|
||||
IssueUUID: issueUUID,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Error) WithCause(cause error) *Error {
|
||||
e.Cause = cause
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Error) ControlError() *rvboxv1.ControlError {
|
||||
return &rvboxv1.ControlError{
|
||||
Code: e.Code,
|
||||
Message: boundUTF8(e.Message, MaxProtocolDetailBytes),
|
||||
Retryable: e.Retryable,
|
||||
IssueUuid: e.IssueUUID,
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultRetryable(code rvboxv1.ControlError_Code) bool {
|
||||
switch code {
|
||||
case rvboxv1.ControlError_OFFLINE,
|
||||
rvboxv1.ControlError_CAPACITY_EXHAUSTED,
|
||||
rvboxv1.ControlError_TRANSIENT,
|
||||
rvboxv1.ControlError_INTERNAL:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func NewExecutionContextUnavailable(message, issueUUID string) *Error {
|
||||
return NewError(rvboxv1.ControlError_CODE_EXECUTION_CONTEXT_UNAVAILABLE, message, issueUUID)
|
||||
}
|
||||
|
||||
func NewElevationUnavailable(message, issueUUID string) *Error {
|
||||
return NewError(rvboxv1.ControlError_CODE_ELEVATION_UNAVAILABLE, message, issueUUID)
|
||||
}
|
||||
|
||||
func boundUTF8(value string, limit int) string {
|
||||
if len(value) <= limit {
|
||||
return value
|
||||
}
|
||||
value = value[:limit]
|
||||
for !utf8.ValidString(value) {
|
||||
value = value[:len(value)-1]
|
||||
}
|
||||
return value
|
||||
}
|
||||
Reference in New Issue
Block a user