github.com/storacha/go-ucanto@v0.7.2/server/error.go (about)

     1  package server
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/storacha/go-ucanto/core/ipld"
     8  	"github.com/storacha/go-ucanto/core/result/failure"
     9  	sdm "github.com/storacha/go-ucanto/server/datamodel"
    10  	"github.com/storacha/go-ucanto/ucan"
    11  )
    12  
    13  type HandlerNotFoundError[Caveats any] interface {
    14  	failure.Failure
    15  	Capability() ucan.Capability[Caveats]
    16  }
    17  
    18  type handlerNotFoundError[Caveats any] struct {
    19  	capability ucan.Capability[Caveats]
    20  }
    21  
    22  func (h handlerNotFoundError[C]) Capability() ucan.Capability[C] {
    23  	return h.capability
    24  }
    25  
    26  func (h handlerNotFoundError[C]) Error() string {
    27  	return fmt.Sprintf("service does not implement {can: \"%s\"} handler", h.capability.Can())
    28  }
    29  
    30  func (h handlerNotFoundError[C]) Name() string {
    31  	return "HandlerNotFoundError"
    32  }
    33  
    34  func (h handlerNotFoundError[C]) ToIPLD() (ipld.Node, error) {
    35  	name := h.Name()
    36  
    37  	mdl := sdm.HandlerNotFoundErrorModel{
    38  		Error:   true,
    39  		Name:    &name,
    40  		Message: h.Error(),
    41  		Capability: sdm.CapabilityModel{
    42  			Can:  h.capability.Can(),
    43  			With: h.capability.With(),
    44  		},
    45  	}
    46  	return ipld.WrapWithRecovery(&mdl, sdm.HandlerNotFoundErrorType())
    47  }
    48  
    49  func NewHandlerNotFoundError[Caveats any](capability ucan.Capability[Caveats]) HandlerNotFoundError[Caveats] {
    50  	return handlerNotFoundError[Caveats]{capability}
    51  }
    52  
    53  type HandlerExecutionError[Caveats any] interface {
    54  	failure.Failure
    55  	failure.WithStackTrace
    56  	Cause() error
    57  	Capability() ucan.Capability[Caveats]
    58  }
    59  
    60  type handlerExecutionError[Caveats any] struct {
    61  	cause      error
    62  	capability ucan.Capability[Caveats]
    63  }
    64  
    65  func (h handlerExecutionError[C]) Capability() ucan.Capability[C] {
    66  	return h.capability
    67  }
    68  
    69  func (h handlerExecutionError[C]) Cause() error {
    70  	return h.cause
    71  }
    72  
    73  func (h handlerExecutionError[C]) Error() string {
    74  	return fmt.Sprintf("service handler {can: \"%s\"} error: %s", h.capability.Can(), h.cause.Error())
    75  }
    76  
    77  func (h handlerExecutionError[C]) Name() string {
    78  	return "HandlerExecutionError"
    79  }
    80  
    81  func (h handlerExecutionError[C]) Stack() string {
    82  	var stack string
    83  	if serr, ok := h.cause.(failure.WithStackTrace); ok {
    84  		stack = serr.Stack()
    85  	}
    86  	return stack
    87  }
    88  
    89  func (h handlerExecutionError[C]) ToIPLD() (ipld.Node, error) {
    90  	name := h.Name()
    91  	stack := h.Stack()
    92  
    93  	var cname string
    94  	if ncause, ok := h.cause.(failure.Named); ok {
    95  		cname = ncause.Name()
    96  	}
    97  
    98  	var cstack string
    99  	if scause, ok := h.cause.(failure.WithStackTrace); ok {
   100  		cstack = scause.Stack()
   101  	}
   102  
   103  	mdl := sdm.HandlerExecutionErrorModel{
   104  		Error:   true,
   105  		Name:    &name,
   106  		Message: h.Error(),
   107  		Stack:   &stack,
   108  		Cause: sdm.FailureModel{
   109  			Name:    &cname,
   110  			Message: h.cause.Error(),
   111  			Stack:   &cstack,
   112  		},
   113  		Capability: sdm.CapabilityModel{
   114  			Can:  h.capability.Can(),
   115  			With: h.capability.With(),
   116  		},
   117  	}
   118  	return ipld.WrapWithRecovery(&mdl, sdm.HandlerExecutionErrorType())
   119  }
   120  
   121  func NewHandlerExecutionError[Caveats any](cause error, capability ucan.Capability[Caveats]) HandlerExecutionError[Caveats] {
   122  	return handlerExecutionError[Caveats]{cause, capability}
   123  }
   124  
   125  type InvocationCapabilityError interface {
   126  	failure.Failure
   127  	Capabilities() []ucan.Capability[any]
   128  }
   129  
   130  type invocationCapabilityError struct {
   131  	capabilities []ucan.Capability[any]
   132  }
   133  
   134  func (i invocationCapabilityError) Capabilities() []ucan.Capability[any] {
   135  	return i.capabilities
   136  }
   137  
   138  func (i invocationCapabilityError) Error() string {
   139  	return "Invocation is required to have a single capability."
   140  }
   141  
   142  func (i invocationCapabilityError) Name() string {
   143  	return "InvocationCapabilityError"
   144  }
   145  
   146  func (i invocationCapabilityError) ToIPLD() (ipld.Node, error) {
   147  	name := i.Name()
   148  	var capmdls []sdm.CapabilityModel
   149  	for _, cap := range i.Capabilities() {
   150  		capmdls = append(capmdls, sdm.CapabilityModel{
   151  			Can:  cap.Can(),
   152  			With: cap.With(),
   153  		})
   154  	}
   155  
   156  	mdl := sdm.InvocationCapabilityErrorModel{
   157  		Error:        true,
   158  		Name:         &name,
   159  		Message:      i.Error(),
   160  		Capabilities: capmdls,
   161  	}
   162  	return ipld.WrapWithRecovery(&mdl, sdm.InvocationCapabilityErrorType())
   163  }
   164  
   165  func NewInvocationCapabilityError(capabilities []ucan.Capability[any]) InvocationCapabilityError {
   166  	return invocationCapabilityError{capabilities}
   167  }
   168  
   169  type InvalidAudienceError struct {
   170  	expected []ucan.Principal
   171  	actual   ucan.Principal
   172  }
   173  
   174  func (i InvalidAudienceError) Error() string {
   175  	expectedStr := make([]string, 0, len(i.expected))
   176  	for _, e := range i.expected {
   177  		expectedStr = append(expectedStr, e.DID().String())
   178  	}
   179  
   180  	return fmt.Sprintf("Invalid audience: expected %s, got %s", strings.Join(expectedStr, " or "), i.actual.DID().String())
   181  }
   182  
   183  func (i InvalidAudienceError) Name() string {
   184  	return "InvalidAudienceError"
   185  }
   186  
   187  func (i InvalidAudienceError) ToIPLD() (ipld.Node, error) {
   188  	name := i.Name()
   189  	mdl := sdm.InvalidAudienceErrorModel{
   190  		Error:   true,
   191  		Name:    &name,
   192  		Message: i.Error(),
   193  	}
   194  	return ipld.WrapWithRecovery(&mdl, sdm.InvalidAudienceErrorType())
   195  }
   196  
   197  func NewInvalidAudienceError(actual ucan.Principal, expected ...ucan.Principal) InvalidAudienceError {
   198  	return InvalidAudienceError{expected, actual}
   199  }