Skip to content

Commit

Permalink
feat!: server (#6)
Browse files Browse the repository at this point in the history
This PR adds a server component to the library. Note that it does not
yet validate incoming payloads.

1. It accepts an `AgentMessage`
2. Pulls out the invocations
3. Executes each invocation, using the capability name to identify the
handler to run
4. Encodes receipts for each invocation
5. Constructs a response `AgentMessage` and returns it

It also has methods for constructing a server and defining invocation
handler functions.

BREAKING CHANGE: referencing this package at web3-storage will no longer
work after this commit due to the way go.mod works

---------

Co-authored-by: hannahhoward <[email protected]>
  • Loading branch information
Alan Shaw and hannahhoward authored Aug 14, 2024
1 parent 6fb87be commit d7e26c4
Show file tree
Hide file tree
Showing 59 changed files with 2,275 additions and 284 deletions.
29 changes: 14 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Ucanto UCAN RPC in Golang.
## Install

```console
go get github.com/web3-storage/go-ucanto
go get github.com/storacha-network/go-ucanto
```

## Usage
Expand All @@ -17,14 +17,14 @@ import (
"net/url"
"ioutil"

"github.com/web3-storage/go-ucanto/client"
"github.com/web3-storage/go-ucanto/did"
ed25519 "github.com/web3-storage/go-ucanto/principal/ed25519/signer"
"github.com/web3-storage/go-ucanto/transport/car"
"github.com/web3-storage/go-ucanto/transport/http"
"github.com/web3-storage/go-ucanto/core/delegation"
"github.com/web3-storage/go-ucanto/core/invocation"
"github.com/web3-storage/go-ucanto/core/receipt"
"github.com/storacha-network/go-ucanto/client"
"github.com/storacha-network/go-ucanto/did"
ed25519 "github.com/storacha-network/go-ucanto/principal/ed25519/signer"
"github.com/storacha-network/go-ucanto/transport/car"
"github.com/storacha-network/go-ucanto/transport/http"
"github.com/storacha-network/go-ucanto/core/delegation"
"github.com/storacha-network/go-ucanto/core/invocation"
"github.com/storacha-network/go-ucanto/core/receipt"
)

// service URL & DID
Expand Down Expand Up @@ -62,9 +62,8 @@ capability := ucan.NewCapability(
)

// create invocation(s) to perform a task with granted capabilities
invocations := []invocation.Invocation{
invocation.Invoke(signer, audience, capability, delegation.WithProofs(...))
}
inv, _ := invocation.Invoke(signer, audience, capability, delegation.WithProofs(...))
invocations := []invocation.Invocation{inv}

// send the invocation(s) to the service
resp, _ := client.Execute(invocations, conn)
Expand Down Expand Up @@ -104,15 +103,15 @@ fmt.Println(rcpt.Out().Ok())

## API

[pkg.go.dev Reference](https://pkg.go.dev/github.com/web3-storage/go-ucanto)
[pkg.go.dev Reference](https://pkg.go.dev/github.com/storacha-network/go-ucanto)

## Related

* [Ucanto in Javascript](https://github.com/web3-storage/ucanto)
* [Ucanto in Javascript](https://github.com/storacha-network/ucanto)

## Contributing

Feel free to join in. All welcome. Please [open an issue](https://github.com/web3-storage/go-ucanto/issues)!
Feel free to join in. All welcome. Please [open an issue](https://github.com/storacha-network/go-ucanto/issues)!

## License

Expand Down
40 changes: 31 additions & 9 deletions client/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import (
"fmt"
"hash"

"github.com/web3-storage/go-ucanto/core/invocation"
"github.com/web3-storage/go-ucanto/core/ipld/block"
"github.com/web3-storage/go-ucanto/core/iterable"
"github.com/web3-storage/go-ucanto/core/message"
"github.com/web3-storage/go-ucanto/transport"
"github.com/web3-storage/go-ucanto/ucan"
"github.com/storacha-network/go-ucanto/core/invocation"
"github.com/storacha-network/go-ucanto/core/ipld/block"
"github.com/storacha-network/go-ucanto/core/iterable"
"github.com/storacha-network/go-ucanto/core/message"
"github.com/storacha-network/go-ucanto/transport"
"github.com/storacha-network/go-ucanto/transport/car"
"github.com/storacha-network/go-ucanto/ucan"
)

type Connection interface {
Expand All @@ -25,6 +26,7 @@ type Option func(cfg *connConfig) error

type connConfig struct {
hasher func() hash.Hash
codec transport.OutboundCodec
}

// WithHasher configures the hasher factory.
Expand All @@ -35,14 +37,34 @@ func WithHasher(hasher func() hash.Hash) Option {
}
}

func NewConnection(id ucan.Principal, codec transport.OutboundCodec, channel transport.Channel, options ...Option) (Connection, error) {
cfg := connConfig{sha256.New}
// WithOutboundCodec configures the codec used to encode requests and decode
// responses.
func WithOutboundCodec(codec transport.OutboundCodec) Option {
return func(cfg *connConfig) error {
cfg.codec = codec
return nil
}
}

func NewConnection(id ucan.Principal, channel transport.Channel, options ...Option) (Connection, error) {
cfg := connConfig{hasher: sha256.New}
for _, opt := range options {
if err := opt(&cfg); err != nil {
return nil, err
}
}
c := conn{id, codec, channel, cfg.hasher}

hasher := cfg.hasher
if hasher == nil {
hasher = sha256.New
}

codec := cfg.codec
if codec == nil {
codec = car.NewCAROutboundCodec()
}

c := conn{id, codec, channel, hasher}
return &c, nil
}

Expand Down
6 changes: 3 additions & 3 deletions core/car/car.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
ipldcar "github.com/ipld/go-car"
"github.com/ipld/go-car/util"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
"github.com/web3-storage/go-ucanto/core/ipld"
"github.com/web3-storage/go-ucanto/core/ipld/block"
"github.com/web3-storage/go-ucanto/core/iterable"
"github.com/storacha-network/go-ucanto/core/ipld"
"github.com/storacha-network/go-ucanto/core/ipld/block"
"github.com/storacha-network/go-ucanto/core/iterable"
)

// ContentType is the value the HTTP Content-Type header should have for CARs.
Expand Down
2 changes: 1 addition & 1 deletion core/car/car_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

"github.com/ipfs/go-cid"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
"github.com/web3-storage/go-ucanto/core/ipld"
"github.com/storacha-network/go-ucanto/core/ipld"
)

type fixture struct {
Expand Down
4 changes: 2 additions & 2 deletions core/dag/blockstore/blockstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"io"
"sync"

"github.com/web3-storage/go-ucanto/core/ipld"
"github.com/web3-storage/go-ucanto/core/iterable"
"github.com/storacha-network/go-ucanto/core/ipld"
"github.com/storacha-network/go-ucanto/core/iterable"
)

type BlockReader interface {
Expand Down
8 changes: 4 additions & 4 deletions core/delegation/datamodel/archive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import (

"github.com/ipfs/go-cid"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
adm "github.com/web3-storage/go-ucanto/core/delegation/datamodel"
"github.com/web3-storage/go-ucanto/core/ipld/block"
"github.com/web3-storage/go-ucanto/core/ipld/codec/cbor"
"github.com/web3-storage/go-ucanto/core/ipld/hash/sha256"
adm "github.com/storacha-network/go-ucanto/core/delegation/datamodel"
"github.com/storacha-network/go-ucanto/core/ipld/block"
"github.com/storacha-network/go-ucanto/core/ipld/codec/cbor"
"github.com/storacha-network/go-ucanto/core/ipld/hash/sha256"
)

func TestEncodeDecode(t *testing.T) {
Expand Down
12 changes: 6 additions & 6 deletions core/delegation/delegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package delegation
import (
"fmt"

"github.com/web3-storage/go-ucanto/core/dag/blockstore"
"github.com/web3-storage/go-ucanto/core/ipld/block"
"github.com/web3-storage/go-ucanto/core/ipld/codec/cbor"
"github.com/web3-storage/go-ucanto/core/ipld/hash/sha256"
"github.com/web3-storage/go-ucanto/ucan"
udm "github.com/web3-storage/go-ucanto/ucan/datamodel/ucan"
"github.com/storacha-network/go-ucanto/core/dag/blockstore"
"github.com/storacha-network/go-ucanto/core/ipld/block"
"github.com/storacha-network/go-ucanto/core/ipld/codec/cbor"
"github.com/storacha-network/go-ucanto/core/ipld/hash/sha256"
"github.com/storacha-network/go-ucanto/ucan"
udm "github.com/storacha-network/go-ucanto/ucan/datamodel/ucan"
)

// Option is an option configuring a UCAN delegation.
Expand Down
22 changes: 11 additions & 11 deletions core/delegation/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import (
"io"
"sync"

"github.com/web3-storage/go-ucanto/core/car"
"github.com/web3-storage/go-ucanto/core/dag/blockstore"
adm "github.com/web3-storage/go-ucanto/core/delegation/datamodel"
"github.com/web3-storage/go-ucanto/core/ipld"
"github.com/web3-storage/go-ucanto/core/ipld/block"
"github.com/web3-storage/go-ucanto/core/ipld/codec/cbor"
"github.com/web3-storage/go-ucanto/core/ipld/hash/sha256"
"github.com/web3-storage/go-ucanto/core/iterable"
"github.com/web3-storage/go-ucanto/ucan"
"github.com/web3-storage/go-ucanto/ucan/crypto/signature"
udm "github.com/web3-storage/go-ucanto/ucan/datamodel/ucan"
"github.com/storacha-network/go-ucanto/core/car"
"github.com/storacha-network/go-ucanto/core/dag/blockstore"
adm "github.com/storacha-network/go-ucanto/core/delegation/datamodel"
"github.com/storacha-network/go-ucanto/core/ipld"
"github.com/storacha-network/go-ucanto/core/ipld/block"
"github.com/storacha-network/go-ucanto/core/ipld/codec/cbor"
"github.com/storacha-network/go-ucanto/core/ipld/hash/sha256"
"github.com/storacha-network/go-ucanto/core/iterable"
"github.com/storacha-network/go-ucanto/ucan"
"github.com/storacha-network/go-ucanto/ucan/crypto/signature"
udm "github.com/storacha-network/go-ucanto/ucan/datamodel/ucan"
)

// Delagation is a materialized view of a UCAN delegation, which can be encoded
Expand Down
6 changes: 3 additions & 3 deletions core/delegation/proofs.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package delegation

import (
"github.com/web3-storage/go-ucanto/core/dag/blockstore"
"github.com/web3-storage/go-ucanto/core/ipld"
"github.com/web3-storage/go-ucanto/ucan"
"github.com/storacha-network/go-ucanto/core/dag/blockstore"
"github.com/storacha-network/go-ucanto/core/ipld"
"github.com/storacha-network/go-ucanto/ucan"
)

type Proof struct {
Expand Down
44 changes: 7 additions & 37 deletions core/invocation/invocation.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package invocation

import (
"github.com/web3-storage/go-ucanto/core/dag/blockstore"
"github.com/web3-storage/go-ucanto/core/delegation"
"github.com/web3-storage/go-ucanto/core/ipld"
"github.com/web3-storage/go-ucanto/ucan"
"github.com/storacha-network/go-ucanto/core/dag/blockstore"
"github.com/storacha-network/go-ucanto/core/delegation"
"github.com/storacha-network/go-ucanto/core/ipld"
"github.com/storacha-network/go-ucanto/ucan"
)

// Invocation represents a UCAN that can be presented to a service provider to
Expand Down Expand Up @@ -32,37 +32,7 @@ type IssuedInvocation interface {
Invocation
}

func Invoke(issuer ucan.Signer, audience ucan.Principal, capability ucan.Capability[ucan.CaveatBuilder], options ...delegation.Option) (IssuedInvocation, error) {
return delegation.Delegate(issuer, audience, []ucan.Capability[ucan.CaveatBuilder]{capability}, options...)
}

type Ran struct {
invocation Invocation
link ucan.Link
}

func (r Ran) Invocation() (Invocation, bool) {
return r.invocation, r.invocation != nil
}

func (r Ran) Link() ucan.Link {
if r.invocation != nil {
return r.invocation.Link()
}
return r.link
}

func FromInvocation(invocation Invocation) Ran {
return Ran{invocation, nil}
}

func FromLink(link ucan.Link) Ran {
return Ran{nil, link}
}

func (r Ran) WriteInto(bs blockstore.BlockWriter) (ipld.Link, error) {
if invocation, ok := r.Invocation(); ok {
return r.Link(), blockstore.WriteInto(invocation, bs)
}
return r.Link(), nil
func Invoke[C ucan.CaveatBuilder](issuer ucan.Signer, audience ucan.Principal, capability ucan.Capability[C], options ...delegation.Option) (IssuedInvocation, error) {
bcap := ucan.NewCapability(capability.Can(), capability.With(), ucan.CaveatBuilder(capability.Nb()))
return delegation.Delegate(issuer, audience, []ucan.Capability[ucan.CaveatBuilder]{bcap}, options...)
}
39 changes: 39 additions & 0 deletions core/invocation/ran/ran.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package ran

import (
"github.com/storacha-network/go-ucanto/core/dag/blockstore"
"github.com/storacha-network/go-ucanto/core/invocation"
"github.com/storacha-network/go-ucanto/core/ipld"
"github.com/storacha-network/go-ucanto/ucan"
)

type Ran struct {
invocation invocation.Invocation
link ucan.Link
}

func (r Ran) Invocation() (invocation.Invocation, bool) {
return r.invocation, r.invocation != nil
}

func (r Ran) Link() ucan.Link {
if r.invocation != nil {
return r.invocation.Link()
}
return r.link
}

func FromInvocation(invocation invocation.Invocation) Ran {
return Ran{invocation, nil}
}

func FromLink(link ucan.Link) Ran {
return Ran{nil, link}
}

func (r Ran) WriteInto(bs blockstore.BlockWriter) (ipld.Link, error) {
if invocation, ok := r.Invocation(); ok {
return r.Link(), blockstore.WriteInto(invocation, bs)
}
return r.Link(), nil
}
4 changes: 2 additions & 2 deletions core/ipld/block/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (
"github.com/ipld/go-ipld-prime"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
"github.com/ipld/go-ipld-prime/schema"
"github.com/web3-storage/go-ucanto/core/ipld/codec"
"github.com/web3-storage/go-ucanto/core/ipld/hash"
"github.com/storacha-network/go-ucanto/core/ipld/codec"
"github.com/storacha-network/go-ucanto/core/ipld/hash"
)

type Block interface {
Expand Down
2 changes: 1 addition & 1 deletion core/ipld/hash/sha256/sha256.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"crypto/sha256"

"github.com/multiformats/go-multihash"
"github.com/web3-storage/go-ucanto/core/ipld/hash"
"github.com/storacha-network/go-ucanto/core/ipld/hash"
)

// sha2-256
Expand Down
29 changes: 28 additions & 1 deletion core/ipld/lib.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,37 @@
package ipld

import (
"errors"

"github.com/ipld/go-ipld-prime"
"github.com/web3-storage/go-ucanto/core/ipld/block"
"github.com/ipld/go-ipld-prime/node/bindnode"
"github.com/ipld/go-ipld-prime/schema"
"github.com/storacha-network/go-ucanto/core/ipld/block"
)

type Link = ipld.Link
type Block = block.Block
type Node = ipld.Node

// Builder can be modeled as an IPLD data and provides a `Build“ method to
// build itself into a `datamodel.Node`.
type Builder interface {
Build() (Node, error)
}

// WrapWithRecovery behaves like bindnode.Wrap but converts panics into errors
func WrapWithRecovery(ptrVal interface{}, typ schema.Type) (nd Node, err error) {
defer func() {
if r := recover(); r != nil {
if asStr, ok := r.(string); ok {
err = errors.New(asStr)
} else if asErr, ok := r.(error); ok {
err = asErr
} else {
err = errors.New("unknown panic building node")
}
}
}()
nd = bindnode.Wrap(ptrVal, typ)
return
}
Loading

0 comments on commit d7e26c4

Please sign in to comment.