Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions failure/failure.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Package failure defines a drop-in replacement for go-ucanto's failure
// module, with an extended FailureModel that can represent all the fields that
// may appear, so that decoding doesn't fail because of unexpected fields. This
// should ideally move to go-ucanto itself in some form, but it's a bit of a
// hack right now, and the entire issue will go away with the UCAN 1.0 version
// of go-ucanto.
package failure

import (
// to use go:embed
_ "embed"
"fmt"

"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/datamodel"
"github.com/ipld/go-ipld-prime/schema"
ucanipld "github.com/storacha/go-ucanto/core/ipld"
ucantofailure "github.com/storacha/go-ucanto/core/result/failure"
)

//go:embed failure.ipldsch
var failureSchema []byte

// FailureModel is a generic failure
type FailureModel struct {
Name *string
Message string
Stack *string

Audience *ipld.Node //UCANPrincipal
Capability *ipld.Node //Capability
Cause *FailureModel
Causes *[]FailureModel
Claimed *ipld.Node //ParsedCapability
Delegated *ipld.Node //Any
Delegation *ipld.Node //Delegation
DelegationErrors *[]FailureModel
Did *[]byte //DID
ExpiredAt *int64
FailedProofs *[]FailureModel
InvalidProofs *[]FailureModel
Issuer *ipld.Node //UCANPrincipal
Link *datamodel.Link
UnknownCapabilities *[]ipld.Node //[]Capability
ValidAt *int64
IsError *bool
}

func (f FailureModel) Error() string {
return f.Message
}

func (f *FailureModel) ToIPLD() (ipld.Node, error) {
return ucanipld.WrapWithRecovery(f, typ)
}

var typ schema.Type

func init() {
ts, err := ipld.LoadSchemaBytes(failureSchema)
if err != nil {
panic(fmt.Errorf("loading failure schema: %w", err))
}
typ = ts.TypeByName("Failure")
}

func FailureType() schema.Type {
return typ
}

type failure struct {
model FailureModel
toIPLD func() (ipld.Node, error)
}

func (f failure) Name() string {
if f.model.Name == nil {
return ""
}
return *f.model.Name
}

func (f failure) Message() string {
return f.model.Message
}

func (f failure) Error() string {
return f.model.Message
}

func (f failure) Stack() string {
if f.model.Stack == nil {
return ""
}
return *f.model.Stack
}

func (f failure) ToIPLD() (ipld.Node, error) {
if f.toIPLD != nil {
return f.toIPLD()
}
return f.model.ToIPLD()
}

func FromFailureModel(model FailureModel) ucantofailure.IPLDBuilderFailure {
// treat a zero value failure as a non-error
if (model == FailureModel{}) {
return nil
}
return failure{model: model}
}
29 changes: 29 additions & 0 deletions failure/failure.ipldsch
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
type Failure struct {
name optional String
message String
stack optional String

audience optional UCANPrincipal
capability optional Capability
cause optional Failure
causes optional [Failure]
claimed optional ParsedCapability
delegated optional Any
delegation optional Delegation
delegationErrors optional [Failure]
did optional DID
expiredAt optional Int
failedProofs optional [Failure]
invalidProofs optional [Failure]
issuer optional UCANPrincipal
link optional Link
unknownCapabilities optional [Capability]
validAt optional Int
isError optional Bool (rename "error")
}

type UCANPrincipal any
type Capability any
type ParsedCapability any
type Delegation any
type DID bytes