server

package
v0.0.0-...-79141c5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 6, 2026 License: Apache-2.0, MIT Imports: 11 Imported by: 0

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type EventListener

type EventListener interface {
	RequestDecodeListener
	ResponseEncodeListener
}

EventListener observes both halves of the request/response round trip a server handles: a request being decoded and a response being encoded. Register one with WithEventListener.

type HTTPOption

type HTTPOption func(cfg *httpServerConfig)

HTTPOption is an option configuring a UCAN HTTP server.

func WithEventListener

func WithEventListener(listener EventListener) HTTPOption

WithEventListener registers an EventListener to observe the server's requests and responses as they are decoded and encoded.

func WithReceiptTimestamps

func WithReceiptTimestamps(enabled bool) HTTPOption

WithReceiptTimestamps configures the server to issue receipts with issuance timestamps or not.

func WithValidationOptions

func WithValidationOptions(options ...validator.Option) HTTPOption

type HTTPServer

type HTTPServer struct {
	// contains filtered or unexported fields
}

func NewHTTP

func NewHTTP(id ucan.Issuer, options ...HTTPOption) *HTTPServer

NewHTTP creates a new server capable of handling UCAN invocations over HTTP.

func (*HTTPServer) Execute

func (s *HTTPServer) Execute(req execution.Request) (execution.Response, error)

func (*HTTPServer) Handle

func (s *HTTPServer) Handle(command ucan.Command, fn execution.HandlerFunc)

func (*HTTPServer) RoundTrip

func (s *HTTPServer) RoundTrip(r *http.Request) (*http.Response, error)

RoundTrip unpacks and executes an incoming request, returning the response.

func (*HTTPServer) ServeHTTP

func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request)

type RequestDecodeListener

type RequestDecodeListener interface {
	OnRequestDecode(ctx context.Context, container ucan.Container) error
}

RequestDecodeListener is an observer with a function that is called after an execution request has been decoded by the codec.

type ResponseEncodeListener

type ResponseEncodeListener interface {
	OnResponseEncode(ctx context.Context, container ucan.Container) error
}

ResponseEncodeListener is an observer with a function that is called before an execution response is encoded by the codec.

type Route

type Route struct {
	Command ucan.Command
	Handler execution.HandlerFunc
}

Route maps a command to the handler that executes it. A Route can be carried as a value — e.g. collected via dependency injection — and applied to a server later with HTTPServer.Handle:

for _, r := range routes {
	srv.Handle(r.Command, r.Handler)
}

func NewRoute

func NewRoute(cmd ucan.Command, fn execution.HandlerFunc) Route

NewRoute builds a Route from a command and a handler.

Example

ExampleNewRoute bundles commands with their handlers as server.Route values and registers them on a server in one place. Because a Route's command and handler come from the same binding, their argument and result types cannot drift apart. Collecting routes as values also lets independent subsystems each contribute their own and hand them to the server for registration.

package main

import (
	"context"
	"fmt"
	"net/http"
	"net/url"

	"github.com/fil-forge/ucantone/binding"
	"github.com/fil-forge/ucantone/client"
	"github.com/fil-forge/ucantone/execution"
	"github.com/fil-forge/ucantone/multikey/ed25519"
	"github.com/fil-forge/ucantone/server"
	tdm "github.com/fil-forge/ucantone/testutil/datamodel"
	"github.com/fil-forge/ucantone/ucan/command"
	"github.com/fil-forge/ucantone/ucan/invocation"
)

// echo is the /example/echo command bound to the Go types of its arguments and
// result. Handlers and clients both derive their types from it.
var echo = binding.Bind[*tdm.TestObject, *tdm.TestObject2](command.MustParse("/example/echo"))

// ExampleNewRoute bundles commands with their handlers as [server.Route] values
// and registers them on a server in one place. Because a Route's command and
// handler come from the same binding, their argument and result types cannot
// drift apart. Collecting routes as values also lets independent subsystems
// each contribute their own and hand them to the server for registration.
func main() {
	// Each subsystem contributes routes; here, the echo command and a handler
	// that returns the argument bytes as a string.
	routes := []server.Route{
		echo.Route(func(req *binding.Request[*tdm.TestObject], res *binding.Response[*tdm.TestObject2]) error {
			args := req.Task().Arguments()
			return res.SetSuccess(&tdm.TestObject2{Str: string(args.Bytes)})
		}),
	}

	service, _ := ed25519.GenerateIssuer()
	srv := server.NewHTTP(service)
	for _, r := range routes {
		srv.Handle(r.Command, r.Handler)
	}

	// Drive the server in-process by using it as the client's HTTP transport.
	endpoint, _ := url.Parse("http://echo.example")
	c, _ := client.NewHTTP(endpoint, client.WithHTTPClient(&http.Client{Transport: srv}))

	// A client invokes the command with typed arguments and unpacks the typed
	// result from the receipt.
	alice, _ := ed25519.GenerateIssuer()
	inv, _ := echo.Invoke(alice, alice.DID(), &tdm.TestObject{Bytes: []byte("hi")}, invocation.WithAudience(service.DID()))
	resp, _ := c.Execute(execution.NewRequest(context.Background(), inv))

	out, _ := echo.Unpack(resp.Receipt())
	fmt.Println(out.Str)
}
Output:
hi

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL