maybe fixed

This commit is contained in:
Lorenzo Venerandi 2024-12-16 20:34:52 +01:00
parent cdc80d0b53
commit 8cd67e00a2
24 changed files with 1651 additions and 242 deletions

View File

@ -48,5 +48,4 @@ RUN mkdir /app
WORKDIR /app
# Install go dependencies, build the wasm module, push it to the registry
#CMD ["sh", "-c", "go mod download && go mod verify && go mod tidy && wash build && wash push $REGISTRY build/*_s.wasm"]
CMD ["sh", "-c", "go env -w GOFLAGS=-buildvcs=false && go mod download && go mod verify && wash build && wash push $REGISTRY build/*.wasm"]

View File

@ -1,8 +1,4 @@
# HTTP Hello World
This is a simple TinyGo Wasm example that responds with a "Hello World" message for each request.
## Prerequisites
# Prerequisites
- `go` 1.23
- `tinygo` 0.33
@ -20,6 +16,24 @@ wash build
wash push gitea.rebus.ninja/lore/go-nats-client:1.x.x build/go_nats_client_s.wasm
```
## Build and push to the registry using the dockerfile
### Build the cointainer
```bash
docker build -t wash-image-build .
```
### Build the component and push to the registry
First setup your credentials
```bash
export REG_USER=user && export REG_PASS=pass
```
Build and push
```bash
docker run --rm -e REGISTRY=gitea.rebus.ninja/lore/wasm-nats-producer-client:1.0.x -e WASH_REG_USER=$REG_USER -e WASH_REG_PASSWORD=$REG_PASS -v "$(pwd):/app" wash-image-build
```
## Running with wasmtime
You must have wasmtime 25.0.0 for this to work. Make sure to follow the build step above first.

View File

@ -0,0 +1,3 @@
// This file exists for testing this package without WebAssembly,
// allowing empty function bodies with a //go:wasmimport directive.
// See https://pkg.go.dev/cmd/compile for more information.

View File

@ -0,0 +1,22 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
package incominghandler
// Exports represents the caller-defined exports from "wasi:http/incoming-handler@0.2.0".
var Exports struct {
// Handle represents the caller-defined, exported function "handle".
//
// This function is invoked with an incoming HTTP Request, and a resource
// `response-outparam` which provides the capability to reply with an HTTP
// Response. The response is sent by calling the `response-outparam.set`
// method, which allows execution to continue after the response has been
// sent. This enables both streaming to the response body, and performing other
// work.
//
// The implementor of this function must write a response to the
// `response-outparam` before returning, or else the caller will respond
// with an error on its behalf.
//
// handle: func(request: incoming-request, response-out: response-outparam)
Handle func(request IncomingRequest, responseOut ResponseOutparam)
}

View File

@ -0,0 +1,21 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
// Package incominghandler represents the exported interface "wasi:http/incoming-handler@0.2.0".
//
// This interface defines a handler of incoming HTTP Requests. It should
// be exported by components which can respond to HTTP Requests.
package incominghandler
import (
"gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasi/http/types"
)
// IncomingRequest represents the exported type alias "wasi:http/incoming-handler@0.2.0#incoming-request".
//
// See [types.IncomingRequest] for more information.
type IncomingRequest = types.IncomingRequest
// ResponseOutparam represents the exported type alias "wasi:http/incoming-handler@0.2.0#response-outparam".
//
// See [types.ResponseOutparam] for more information.
type ResponseOutparam = types.ResponseOutparam

View File

@ -0,0 +1,18 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
package incominghandler
import (
"github.com/bytecodealliance/wasm-tools-go/cm"
)
// This file contains wasmimport and wasmexport declarations for "wasi:http@0.2.0".
//go:wasmexport wasi:http/incoming-handler@0.2.0#handle
//export wasi:http/incoming-handler@0.2.0#handle
func wasmexport_Handle(request0 uint32, responseOut0 uint32) {
request := cm.Reinterpret[IncomingRequest]((uint32)(request0))
responseOut := cm.Reinterpret[ResponseOutparam]((uint32)(responseOut0))
Exports.Handle(request, responseOut)
return
}

View File

@ -1,6 +1,9 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
// Package outgoinghandler represents the imported interface "wasi:http/outgoing-handler@0.2.0".
//
// This interface defines a handler of outgoing HTTP Requests. It should be
// imported by components which wish to make HTTP Requests.
package outgoinghandler
import (
@ -30,6 +33,17 @@ type ErrorCode = types.ErrorCode
// Handle represents the imported function "handle".
//
// This function is invoked with an outgoing HTTP Request, and it returns
// a resource `future-incoming-response` which represents an HTTP Response
// which may arrive in the future.
//
// The `options` argument accepts optional parameters for the HTTP
// protocol's transport layer.
//
// This function may return an error if the `outgoing-request` is invalid
// or not allowed to be made. Otherwise, protocol errors are reported
// through the `future-incoming-response`.
//
// handle: func(request: outgoing-request, options: option<request-options>) -> result<future-incoming-response,
// error-code>
//

View File

@ -1,6 +1,10 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
// Package types represents the imported interface "wasi:http/types@0.2.0".
//
// This interface defines all of the types and methods for implementing
// HTTP Requests and Responses, both incoming and outgoing, as well as
// their headers, trailers, and bodies.
package types
import (
@ -38,6 +42,8 @@ type Pollable = poll.Pollable
// Method represents the variant "wasi:http/types@0.2.0#method".
//
// This type corresponds to HTTP standard Methods.
//
// variant method {
// get,
// head,
@ -181,6 +187,8 @@ func (v Method) String() string {
// Scheme represents the variant "wasi:http/types@0.2.0#scheme".
//
// This type corresponds to HTTP standard Related Schemes.
//
// variant scheme {
// HTTP,
// HTTPS,
@ -233,6 +241,8 @@ func (v Scheme) String() string {
// DNSErrorPayload represents the record "wasi:http/types@0.2.0#DNS-error-payload".
//
// Defines the case payload type for `DNS-error` above:
//
// record DNS-error-payload {
// rcode: option<string>,
// info-code: option<u16>,
@ -245,6 +255,8 @@ type DNSErrorPayload struct {
// TLSAlertReceivedPayload represents the record "wasi:http/types@0.2.0#TLS-alert-received-payload".
//
// Defines the case payload type for `TLS-alert-received` above:
//
// record TLS-alert-received-payload {
// alert-id: option<u8>,
// alert-message: option<string>,
@ -257,6 +269,8 @@ type TLSAlertReceivedPayload struct {
// FieldSizePayload represents the record "wasi:http/types@0.2.0#field-size-payload".
//
// Defines the case payload type for `HTTP-response-{header,trailer}-size` above:
//
// record field-size-payload {
// field-name: option<string>,
// field-size: option<u32>,
@ -269,6 +283,9 @@ type FieldSizePayload struct {
// ErrorCode represents the variant "wasi:http/types@0.2.0#error-code".
//
// These cases are inspired by the IANA HTTP Proxy Error Types:
// https://www.iana.org/assignments/http-proxy-status/http-proxy-status.xhtml#table-http-proxy-error-types
//
// variant error-code {
// DNS-timeout,
// DNS-error(DNS-error-payload),
@ -717,6 +734,12 @@ func (self *ErrorCode) ConfigurationError() bool {
}
// ErrorCodeInternalError returns a [ErrorCode] of case "internal-error".
//
// This is a catch-all error for anything that doesn't fit cleanly into a
// more specific case. It also includes an optional string for an
// unstructured description of the error. Users should not depend on the
// string for diagnosing errors, as it's not required to be consistent
// between implementations.
func ErrorCodeInternalError(data cm.Option[string]) ErrorCode {
return cm.New[ErrorCode](38, data)
}
@ -775,6 +798,9 @@ func (v ErrorCode) String() string {
// HeaderError represents the variant "wasi:http/types@0.2.0#header-error".
//
// This type enumerates the different kinds of errors that may occur when
// setting or appending to a `fields` resource.
//
// variant header-error {
// invalid-syntax,
// forbidden,
@ -783,8 +809,17 @@ func (v ErrorCode) String() string {
type HeaderError uint8
const (
// This error indicates that a `field-key` or `field-value` was
// syntactically invalid when used with an operation that sets headers in a
// `fields`.
HeaderErrorInvalidSyntax HeaderError = iota
// This error indicates that a forbidden `field-key` was used when trying
// to set a header in a `fields`.
HeaderErrorForbidden
// This error indicates that the operation on the `fields` was not
// permitted because the fields are immutable.
HeaderErrorImmutable
)
@ -801,16 +836,33 @@ func (e HeaderError) String() string {
// FieldKey represents the string "wasi:http/types@0.2.0#field-key".
//
// Field keys are always strings.
//
// type field-key = string
type FieldKey string
// FieldValue represents the list "wasi:http/types@0.2.0#field-value".
//
// Field values should always be ASCII strings. However, in
// reality, HTTP implementations often have to interpret malformed values,
// so they are provided as a list of bytes.
//
// type field-value = list<u8>
type FieldValue cm.List[uint8]
// Fields represents the imported resource "wasi:http/types@0.2.0#fields".
//
// This following block defines the `fields` resource which corresponds to
// HTTP standard Fields. Fields are a common representation used for both
// Headers and Trailers.
//
// A `fields` may be mutable or immutable. A `fields` created using the
// constructor, `from-list`, or `clone` will be mutable, but a `fields`
// resource given by other means (including, but not limited to,
// `incoming-request.headers`, `outgoing-request.headers`) might be be
// immutable. In an immutable fields, the `set`, `append`, and `delete`
// operations will fail with `header-error.immutable`.
//
// resource fields
type Fields cm.Resource
@ -827,6 +879,10 @@ func (self Fields) ResourceDrop() {
// NewFields represents the imported constructor for resource "fields".
//
// Construct an empty HTTP Fields.
//
// The resulting `fields` is mutable.
//
// constructor()
//
//go:nosplit
@ -838,6 +894,22 @@ func NewFields() (result Fields) {
// FieldsFromList represents the imported static function "from-list".
//
// Construct an HTTP Fields.
//
// The resulting `fields` is mutable.
//
// The list represents each key-value pair in the Fields. Keys
// which have multiple values are represented by multiple entries in this
// list with the same key.
//
// The tuple is a pair of the field key, represented as a string, and
// Value, represented as a list of bytes. In a valid Fields, all keys
// and values are valid UTF-8 strings. However, values are not always
// well-formed, so they are represented as a raw list of bytes.
//
// An error result will be returned if any header or value was
// syntactically invalid, or if a header was forbidden.
//
// from-list: static func(entries: list<tuple<field-key, field-value>>) -> result<fields,
// header-error>
//
@ -850,6 +922,11 @@ func FieldsFromList(entries cm.List[cm.Tuple[FieldKey, FieldValue]]) (result cm.
// Append represents the imported method "append".
//
// Append a value for a key. Does not change or delete any existing
// values for that key.
//
// Fails with `header-error.immutable` if the `fields` are immutable.
//
// append: func(name: field-key, value: field-value) -> result<_, header-error>
//
//go:nosplit
@ -863,6 +940,10 @@ func (self Fields) Append(name FieldKey, value FieldValue) (result cm.Result[Hea
// Clone represents the imported method "clone".
//
// Make a deep copy of the Fields. Equivelant in behavior to calling the
// `fields` constructor on the return value of `entries`. The resulting
// `fields` is mutable.
//
// clone: func() -> fields
//
//go:nosplit
@ -875,6 +956,11 @@ func (self Fields) Clone() (result Fields) {
// Delete represents the imported method "delete".
//
// Delete all values for a key. Does nothing if no values for the key
// exist.
//
// Fails with `header-error.immutable` if the `fields` are immutable.
//
// delete: func(name: field-key) -> result<_, header-error>
//
//go:nosplit
@ -887,6 +973,13 @@ func (self Fields) Delete(name FieldKey) (result cm.Result[HeaderError, struct{}
// Entries represents the imported method "entries".
//
// Retrieve the full set of keys and values in the Fields. Like the
// constructor, the list represents each key-value pair.
//
// The outer list represents each key-value pair in the Fields. Keys
// which have multiple values are represented by multiple entries in this
// list with the same key.
//
// entries: func() -> list<tuple<field-key, field-value>>
//
//go:nosplit
@ -898,6 +991,11 @@ func (self Fields) Entries() (result cm.List[cm.Tuple[FieldKey, FieldValue]]) {
// Get represents the imported method "get".
//
// Get all of the values corresponding to a key. If the key is not present
// in this `fields`, an empty list is returned. However, if the key is
// present but empty, this is represented by a list with one or more
// empty field-values present.
//
// get: func(name: field-key) -> list<field-value>
//
//go:nosplit
@ -910,6 +1008,9 @@ func (self Fields) Get(name FieldKey) (result cm.List[FieldValue]) {
// Has represents the imported method "has".
//
// Returns `true` when the key is present in this `fields`. If the key is
// syntactically invalid, `false` is returned.
//
// has: func(name: field-key) -> bool
//
//go:nosplit
@ -923,6 +1024,11 @@ func (self Fields) Has(name FieldKey) (result bool) {
// Set represents the imported method "set".
//
// Set all of the values for a key. Clears any existing values for that
// key, if they have been set.
//
// Fails with `header-error.immutable` if the `fields` are immutable.
//
// set: func(name: field-key, value: list<field-value>) -> result<_, header-error>
//
//go:nosplit
@ -946,6 +1052,8 @@ type Trailers = Fields
// IncomingRequest represents the imported resource "wasi:http/types@0.2.0#incoming-request".
//
// Represents an incoming HTTP Request.
//
// resource incoming-request
type IncomingRequest cm.Resource
@ -962,6 +1070,8 @@ func (self IncomingRequest) ResourceDrop() {
// Authority represents the imported method "authority".
//
// Returns the authority from the request, if it was present.
//
// authority: func() -> option<string>
//
//go:nosplit
@ -973,6 +1083,9 @@ func (self IncomingRequest) Authority() (result cm.Option[string]) {
// Consume represents the imported method "consume".
//
// Gives the `incoming-body` associated with this request. Will only
// return success at most once, and subsequent calls will return error.
//
// consume: func() -> result<incoming-body>
//
//go:nosplit
@ -984,6 +1097,15 @@ func (self IncomingRequest) Consume() (result cm.Result[IncomingBody, IncomingBo
// Headers represents the imported method "headers".
//
// Get the `headers` associated with the request.
//
// The returned `headers` resource is immutable: `set`, `append`, and
// `delete` operations will fail with `header-error.immutable`.
//
// The `headers` returned are a child resource: it must be dropped before
// the parent `incoming-request` is dropped. Dropping this
// `incoming-request` before all children are dropped will trap.
//
// headers: func() -> headers
//
//go:nosplit
@ -996,6 +1118,8 @@ func (self IncomingRequest) Headers() (result Headers) {
// Method represents the imported method "method".
//
// Returns the method of the incoming request.
//
// method: func() -> method
//
//go:nosplit
@ -1007,6 +1131,8 @@ func (self IncomingRequest) Method() (result Method) {
// PathWithQuery represents the imported method "path-with-query".
//
// Returns the path with query parameters from the request, as a string.
//
// path-with-query: func() -> option<string>
//
//go:nosplit
@ -1018,6 +1144,8 @@ func (self IncomingRequest) PathWithQuery() (result cm.Option[string]) {
// Scheme represents the imported method "scheme".
//
// Returns the protocol scheme from the request.
//
// scheme: func() -> option<scheme>
//
//go:nosplit
@ -1029,6 +1157,8 @@ func (self IncomingRequest) Scheme() (result cm.Option[Scheme]) {
// OutgoingRequest represents the imported resource "wasi:http/types@0.2.0#outgoing-request".
//
// Represents an outgoing HTTP Request.
//
// resource outgoing-request
type OutgoingRequest cm.Resource
@ -1045,6 +1175,17 @@ func (self OutgoingRequest) ResourceDrop() {
// NewOutgoingRequest represents the imported constructor for resource "outgoing-request".
//
// Construct a new `outgoing-request` with a default `method` of `GET`, and
// `none` values for `path-with-query`, `scheme`, and `authority`.
//
// * `headers` is the HTTP Headers for the Request.
//
// It is possible to construct, or manipulate with the accessor functions
// below, an `outgoing-request` with an invalid combination of `scheme`
// and `authority`, or `headers` which are not permitted to be sent.
// It is the obligation of the `outgoing-handler.handle` implementation
// to reject invalid constructions of `outgoing-request`.
//
// constructor(headers: headers)
//
//go:nosplit
@ -1057,6 +1198,10 @@ func NewOutgoingRequest(headers Headers) (result OutgoingRequest) {
// Authority represents the imported method "authority".
//
// Get the HTTP Authority for the Request. A value of `none` may be used
// with Related Schemes which do not require an Authority. The HTTP and
// HTTPS schemes always require an authority.
//
// authority: func() -> option<string>
//
//go:nosplit
@ -1068,6 +1213,13 @@ func (self OutgoingRequest) Authority() (result cm.Option[string]) {
// Body represents the imported method "body".
//
// Returns the resource corresponding to the outgoing Body for this
// Request.
//
// Returns success on the first call: the `outgoing-body` resource for
// this `outgoing-request` can be retrieved at most once. Subsequent
// calls will return error.
//
// body: func() -> result<outgoing-body>
//
//go:nosplit
@ -1079,6 +1231,15 @@ func (self OutgoingRequest) Body() (result cm.Result[OutgoingBody, OutgoingBody,
// Headers represents the imported method "headers".
//
// Get the headers associated with the Request.
//
// The returned `headers` resource is immutable: `set`, `append`, and
// `delete` operations will fail with `header-error.immutable`.
//
// This headers resource is a child: it must be dropped before the parent
// `outgoing-request` is dropped, or its ownership is transfered to
// another component by e.g. `outgoing-handler.handle`.
//
// headers: func() -> headers
//
//go:nosplit
@ -1091,6 +1252,8 @@ func (self OutgoingRequest) Headers() (result Headers) {
// Method represents the imported method "method".
//
// Get the Method for the Request.
//
// method: func() -> method
//
//go:nosplit
@ -1102,6 +1265,9 @@ func (self OutgoingRequest) Method() (result Method) {
// PathWithQuery represents the imported method "path-with-query".
//
// Get the combination of the HTTP Path and Query for the Request.
// When `none`, this represents an empty Path and empty Query.
//
// path-with-query: func() -> option<string>
//
//go:nosplit
@ -1113,6 +1279,9 @@ func (self OutgoingRequest) PathWithQuery() (result cm.Option[string]) {
// Scheme represents the imported method "scheme".
//
// Get the HTTP Related Scheme for the Request. When `none`, the
// implementation may choose an appropriate default scheme.
//
// scheme: func() -> option<scheme>
//
//go:nosplit
@ -1124,6 +1293,11 @@ func (self OutgoingRequest) Scheme() (result cm.Option[Scheme]) {
// SetAuthority represents the imported method "set-authority".
//
// Set the HTTP Authority for the Request. A value of `none` may be used
// with Related Schemes which do not require an Authority. The HTTP and
// HTTPS schemes always require an authority. Fails if the string given is
// not a syntactically valid uri authority.
//
// set-authority: func(authority: option<string>) -> result
//
//go:nosplit
@ -1137,6 +1311,9 @@ func (self OutgoingRequest) SetAuthority(authority cm.Option[string]) (result cm
// SetMethod represents the imported method "set-method".
//
// Set the Method for the Request. Fails if the string present in a
// `method.other` argument is not a syntactically valid method.
//
// set-method: func(method: method) -> result
//
//go:nosplit
@ -1150,6 +1327,10 @@ func (self OutgoingRequest) SetMethod(method Method) (result cm.BoolResult) {
// SetPathWithQuery represents the imported method "set-path-with-query".
//
// Set the combination of the HTTP Path and Query for the Request.
// When `none`, this represents an empty Path and empty Query. Fails is the
// string given is not a syntactically valid path and query uri component.
//
// set-path-with-query: func(path-with-query: option<string>) -> result
//
//go:nosplit
@ -1163,6 +1344,10 @@ func (self OutgoingRequest) SetPathWithQuery(pathWithQuery cm.Option[string]) (r
// SetScheme represents the imported method "set-scheme".
//
// Set the HTTP Related Scheme for the Request. When `none`, the
// implementation may choose an appropriate default scheme. Fails if the
// string given is not a syntactically valid uri scheme.
//
// set-scheme: func(scheme: option<scheme>) -> result
//
//go:nosplit
@ -1176,6 +1361,13 @@ func (self OutgoingRequest) SetScheme(scheme cm.Option[Scheme]) (result cm.BoolR
// RequestOptions represents the imported resource "wasi:http/types@0.2.0#request-options".
//
// Parameters for making an HTTP Request. Each of these parameters is
// currently an optional timeout applicable to the transport layer of the
// HTTP protocol.
//
// These timeouts are separate from any the user may use to bound a
// blocking call to `wasi:io/poll.poll`.
//
// resource request-options
type RequestOptions cm.Resource
@ -1192,6 +1384,8 @@ func (self RequestOptions) ResourceDrop() {
// NewRequestOptions represents the imported constructor for resource "request-options".
//
// Construct a default `request-options` value.
//
// constructor()
//
//go:nosplit
@ -1203,6 +1397,9 @@ func NewRequestOptions() (result RequestOptions) {
// BetweenBytesTimeout represents the imported method "between-bytes-timeout".
//
// The timeout for receiving subsequent chunks of bytes in the Response
// body stream.
//
// between-bytes-timeout: func() -> option<duration>
//
//go:nosplit
@ -1214,6 +1411,8 @@ func (self RequestOptions) BetweenBytesTimeout() (result cm.Option[Duration]) {
// ConnectTimeout represents the imported method "connect-timeout".
//
// The timeout for the initial connect to the HTTP Server.
//
// connect-timeout: func() -> option<duration>
//
//go:nosplit
@ -1225,6 +1424,8 @@ func (self RequestOptions) ConnectTimeout() (result cm.Option[Duration]) {
// FirstByteTimeout represents the imported method "first-byte-timeout".
//
// The timeout for receiving the first byte of the Response body.
//
// first-byte-timeout: func() -> option<duration>
//
//go:nosplit
@ -1236,6 +1437,10 @@ func (self RequestOptions) FirstByteTimeout() (result cm.Option[Duration]) {
// SetBetweenBytesTimeout represents the imported method "set-between-bytes-timeout".
//
// Set the timeout for receiving subsequent chunks of bytes in the Response
// body stream. An error return value indicates that this timeout is not
// supported.
//
// set-between-bytes-timeout: func(duration: option<duration>) -> result
//
//go:nosplit
@ -1249,6 +1454,9 @@ func (self RequestOptions) SetBetweenBytesTimeout(duration cm.Option[Duration])
// SetConnectTimeout represents the imported method "set-connect-timeout".
//
// Set the timeout for the initial connect to the HTTP Server. An error
// return value indicates that this timeout is not supported.
//
// set-connect-timeout: func(duration: option<duration>) -> result
//
//go:nosplit
@ -1262,6 +1470,9 @@ func (self RequestOptions) SetConnectTimeout(duration cm.Option[Duration]) (resu
// SetFirstByteTimeout represents the imported method "set-first-byte-timeout".
//
// Set the timeout for receiving the first byte of the Response body. An
// error return value indicates that this timeout is not supported.
//
// set-first-byte-timeout: func(duration: option<duration>) -> result
//
//go:nosplit
@ -1275,6 +1486,12 @@ func (self RequestOptions) SetFirstByteTimeout(duration cm.Option[Duration]) (re
// ResponseOutparam represents the imported resource "wasi:http/types@0.2.0#response-outparam".
//
// Represents the ability to send an HTTP Response.
//
// This resource is used by the `wasi:http/incoming-handler` interface to
// allow a Response to be sent corresponding to the Request provided as the
// other argument to `incoming-handler.handle`.
//
// resource response-outparam
type ResponseOutparam cm.Resource
@ -1291,6 +1508,16 @@ func (self ResponseOutparam) ResourceDrop() {
// ResponseOutparamSet represents the imported static function "set".
//
// Set the value of the `response-outparam` to either send a response,
// or indicate an error.
//
// This method consumes the `response-outparam` to ensure that it is
// called at most once. If it is never called, the implementation
// will respond with an error.
//
// The user may provide an `error` to `response` to allow the
// implementation determine how to respond with an HTTP error response.
//
// set: static func(param: response-outparam, response: result<outgoing-response,
// error-code>)
//
@ -1304,11 +1531,15 @@ func ResponseOutparamSet(param ResponseOutparam, response cm.Result[ErrorCodeSha
// StatusCode represents the u16 "wasi:http/types@0.2.0#status-code".
//
// This type corresponds to the HTTP standard Status Code.
//
// type status-code = u16
type StatusCode uint16
// IncomingResponse represents the imported resource "wasi:http/types@0.2.0#incoming-response".
//
// Represents an incoming HTTP Response.
//
// resource incoming-response
type IncomingResponse cm.Resource
@ -1325,6 +1556,9 @@ func (self IncomingResponse) ResourceDrop() {
// Consume represents the imported method "consume".
//
// Returns the incoming body. May be called at most once. Returns error
// if called additional times.
//
// consume: func() -> result<incoming-body>
//
//go:nosplit
@ -1336,6 +1570,14 @@ func (self IncomingResponse) Consume() (result cm.Result[IncomingBody, IncomingB
// Headers represents the imported method "headers".
//
// Returns the headers from the incoming response.
//
// The returned `headers` resource is immutable: `set`, `append`, and
// `delete` operations will fail with `header-error.immutable`.
//
// This headers resource is a child: it must be dropped before the parent
// `incoming-response` is dropped.
//
// headers: func() -> headers
//
//go:nosplit
@ -1348,6 +1590,8 @@ func (self IncomingResponse) Headers() (result Headers) {
// Status represents the imported method "status".
//
// Returns the status code from the incoming response.
//
// status: func() -> status-code
//
//go:nosplit
@ -1360,6 +1604,15 @@ func (self IncomingResponse) Status() (result StatusCode) {
// IncomingBody represents the imported resource "wasi:http/types@0.2.0#incoming-body".
//
// Represents an incoming HTTP Request or Response's Body.
//
// A body has both its contents - a stream of bytes - and a (possibly
// empty) set of trailers, indicating that the full contents of the
// body have been received. This resource represents the contents as
// an `input-stream` and the delivery of trailers as a `future-trailers`,
// and ensures that the user of this interface may only be consuming either
// the body contents or waiting on trailers at any given time.
//
// resource incoming-body
type IncomingBody cm.Resource
@ -1376,6 +1629,9 @@ func (self IncomingBody) ResourceDrop() {
// IncomingBodyFinish represents the imported static function "finish".
//
// Takes ownership of `incoming-body`, and returns a `future-trailers`.
// This function will trap if the `input-stream` child is still alive.
//
// finish: static func(this: incoming-body) -> future-trailers
//
//go:nosplit
@ -1388,6 +1644,22 @@ func IncomingBodyFinish(this IncomingBody) (result FutureTrailers) {
// Stream represents the imported method "stream".
//
// Returns the contents of the body, as a stream of bytes.
//
// Returns success on first call: the stream representing the contents
// can be retrieved at most once. Subsequent calls will return error.
//
// The returned `input-stream` resource is a child: it must be dropped
// before the parent `incoming-body` is dropped, or consumed by
// `incoming-body.finish`.
//
// This invariant ensures that the implementation can determine whether
// the user is consuming the contents of the body, waiting on the
// `future-trailers` to be ready, or neither. This allows for network
// backpressure is to be applied when the user is consuming the body,
// and for that backpressure to not inhibit delivery of the trailers if
// the user does not read the entire body.
//
// %stream: func() -> result<input-stream>
//
//go:nosplit
@ -1399,6 +1671,12 @@ func (self IncomingBody) Stream() (result cm.Result[InputStream, InputStream, st
// FutureTrailers represents the imported resource "wasi:http/types@0.2.0#future-trailers".
//
// Represents a future which may eventaully return trailers, or an error.
//
// In the case that the incoming HTTP Request or Response did not have any
// trailers, this future will resolve to the empty set of trailers once the
// complete Request or Response body has been received.
//
// resource future-trailers
type FutureTrailers cm.Resource
@ -1415,6 +1693,26 @@ func (self FutureTrailers) ResourceDrop() {
// Get represents the imported method "get".
//
// Returns the contents of the trailers, or an error which occured,
// once the future is ready.
//
// The outer `option` represents future readiness. Users can wait on this
// `option` to become `some` using the `subscribe` method.
//
// The outer `result` is used to retrieve the trailers or error at most
// once. It will be success on the first call in which the outer option
// is `some`, and error on subsequent calls.
//
// The inner `result` represents that either the HTTP Request or Response
// body, as well as any trailers, were received successfully, or that an
// error occured receiving them. The optional `trailers` indicates whether
// or not trailers were present in the body.
//
// When some `trailers` are returned by this method, the `trailers`
// resource is immutable, and a child. Use of the `set`, `append`, or
// `delete` methods will return an error, and the resource must be
// dropped before the parent `future-trailers` is dropped.
//
// get: func() -> option<result<result<option<trailers>, error-code>>>
//
//go:nosplit
@ -1426,6 +1724,10 @@ func (self FutureTrailers) Get() (result cm.Option[cm.Result[cm.Result[ErrorCode
// Subscribe represents the imported method "subscribe".
//
// Returns a pollable which becomes ready when either the trailers have
// been received, or an error has occured. When this pollable is ready,
// the `get` method will return `some`.
//
// subscribe: func() -> pollable
//
//go:nosplit
@ -1438,6 +1740,8 @@ func (self FutureTrailers) Subscribe() (result Pollable) {
// OutgoingResponse represents the imported resource "wasi:http/types@0.2.0#outgoing-response".
//
// Represents an outgoing HTTP Response.
//
// resource outgoing-response
type OutgoingResponse cm.Resource
@ -1454,6 +1758,12 @@ func (self OutgoingResponse) ResourceDrop() {
// NewOutgoingResponse represents the imported constructor for resource "outgoing-response".
//
// Construct an `outgoing-response`, with a default `status-code` of `200`.
// If a different `status-code` is needed, it must be set via the
// `set-status-code` method.
//
// * `headers` is the HTTP Headers for the Response.
//
// constructor(headers: headers)
//
//go:nosplit
@ -1466,6 +1776,12 @@ func NewOutgoingResponse(headers Headers) (result OutgoingResponse) {
// Body represents the imported method "body".
//
// Returns the resource corresponding to the outgoing Body for this Response.
//
// Returns success on the first call: the `outgoing-body` resource for
// this `outgoing-response` can be retrieved at most once. Subsequent
// calls will return error.
//
// body: func() -> result<outgoing-body>
//
//go:nosplit
@ -1477,6 +1793,15 @@ func (self OutgoingResponse) Body() (result cm.Result[OutgoingBody, OutgoingBody
// Headers represents the imported method "headers".
//
// Get the headers associated with the Request.
//
// The returned `headers` resource is immutable: `set`, `append`, and
// `delete` operations will fail with `header-error.immutable`.
//
// This headers resource is a child: it must be dropped before the parent
// `outgoing-request` is dropped, or its ownership is transfered to
// another component by e.g. `outgoing-handler.handle`.
//
// headers: func() -> headers
//
//go:nosplit
@ -1489,6 +1814,9 @@ func (self OutgoingResponse) Headers() (result Headers) {
// SetStatusCode represents the imported method "set-status-code".
//
// Set the HTTP Status Code for the Response. Fails if the status-code
// given is not a valid http status code.
//
// set-status-code: func(status-code: status-code) -> result
//
//go:nosplit
@ -1502,6 +1830,8 @@ func (self OutgoingResponse) SetStatusCode(statusCode StatusCode) (result cm.Boo
// StatusCode represents the imported method "status-code".
//
// Get the HTTP Status Code for the Response.
//
// status-code: func() -> status-code
//
//go:nosplit
@ -1514,6 +1844,23 @@ func (self OutgoingResponse) StatusCode() (result StatusCode) {
// OutgoingBody represents the imported resource "wasi:http/types@0.2.0#outgoing-body".
//
// Represents an outgoing HTTP Request or Response's Body.
//
// A body has both its contents - a stream of bytes - and a (possibly
// empty) set of trailers, inducating the full contents of the body
// have been sent. This resource represents the contents as an
// `output-stream` child resource, and the completion of the body (with
// optional trailers) with a static function that consumes the
// `outgoing-body` resource, and ensures that the user of this interface
// may not write to the body contents after the body has been finished.
//
// If the user code drops this resource, as opposed to calling the static
// method `finish`, the implementation should treat the body as incomplete,
// and that an error has occured. The implementation should propogate this
// error to the HTTP protocol by whatever means it has available,
// including: corrupting the body on the wire, aborting the associated
// Request, or sending a late status code for the Response.
//
// resource outgoing-body
type OutgoingBody cm.Resource
@ -1530,6 +1877,16 @@ func (self OutgoingBody) ResourceDrop() {
// OutgoingBodyFinish represents the imported static function "finish".
//
// Finalize an outgoing body, optionally providing trailers. This must be
// called to signal that the response is complete. If the `outgoing-body`
// is dropped without calling `outgoing-body.finalize`, the implementation
// should treat the body as corrupted.
//
// Fails if the body's `outgoing-request` or `outgoing-response` was
// constructed with a Content-Length header, and the contents written
// to the body (via `write`) does not match the value given in the
// Content-Length.
//
// finish: static func(this: outgoing-body, trailers: option<trailers>) -> result<_,
// error-code>
//
@ -1543,6 +1900,16 @@ func OutgoingBodyFinish(this OutgoingBody, trailers cm.Option[Trailers]) (result
// Write represents the imported method "write".
//
// Returns a stream for writing the body contents.
//
// The returned `output-stream` is a child resource: it must be dropped
// before the parent `outgoing-body` resource is dropped (or finished),
// otherwise the `outgoing-body` drop or `finish` will trap.
//
// Returns success on the first call: the `output-stream` resource for
// this `outgoing-body` may be retrieved at most once. Subsequent calls
// will return error.
//
// write: func() -> result<output-stream>
//
//go:nosplit
@ -1554,6 +1921,12 @@ func (self OutgoingBody) Write() (result cm.Result[OutputStream, OutputStream, s
// FutureIncomingResponse represents the imported resource "wasi:http/types@0.2.0#future-incoming-response".
//
// Represents a future which may eventaully return an incoming HTTP
// Response, or an error.
//
// This resource is returned by the `wasi:http/outgoing-handler` interface to
// provide the HTTP Response corresponding to the sent Request.
//
// resource future-incoming-response
type FutureIncomingResponse cm.Resource
@ -1570,6 +1943,21 @@ func (self FutureIncomingResponse) ResourceDrop() {
// Get represents the imported method "get".
//
// Returns the incoming HTTP Response, or an error, once one is ready.
//
// The outer `option` represents future readiness. Users can wait on this
// `option` to become `some` using the `subscribe` method.
//
// The outer `result` is used to retrieve the response or error at most
// once. It will be success on the first call in which the outer option
// is `some`, and error on subsequent calls.
//
// The inner `result` represents that either the incoming HTTP Response
// status and headers have recieved successfully, or that an error
// occured. Errors may also occur while consuming the response body,
// but those will be reported by the `incoming-body` and its
// `output-stream` child.
//
// get: func() -> option<result<result<incoming-response, error-code>>>
//
//go:nosplit
@ -1581,6 +1969,10 @@ func (self FutureIncomingResponse) Get() (result cm.Option[cm.Result[cm.Result[E
// Subscribe represents the imported method "subscribe".
//
// Returns a pollable which becomes ready when either the Response has
// been received, or an error has occured. When this pollable is ready,
// the `get` method will return `some`.
//
// subscribe: func() -> pollable
//
//go:nosplit
@ -1593,6 +1985,18 @@ func (self FutureIncomingResponse) Subscribe() (result Pollable) {
// HTTPErrorCode represents the imported function "http-error-code".
//
// Attempts to extract a http-related `error` from the wasi:io `error`
// provided.
//
// Stream operations which return
// `wasi:io/stream/stream-error::last-operation-failed` have a payload of
// type `wasi:io/error/error` with more information about the operation
// that failed. This payload can be passed through to this function to see
// if there's http-related information about the error to return.
//
// Note that this function is fallible because not all io-errors are
// http-related errors.
//
// http-error-code: func(err: borrow<io-error>) -> option<error-code>
//
//go:nosplit

View File

@ -38,77 +38,8 @@ package wasmcloud:hello {
import wasi:random/random@0.2.0;
import wasi:random/insecure@0.2.0;
import wasi:random/insecure-seed@0.2.0;
}
}
package wasi:cli@0.2.0 {
interface environment {
get-environment: func() -> list<tuple<string, string>>;
get-arguments: func() -> list<string>;
initial-cwd: func() -> option<string>;
}
interface exit {
exit: func(status: result);
}
interface stdin {
use wasi:io/streams@0.2.0.{input-stream};
get-stdin: func() -> input-stream;
}
interface stdout {
use wasi:io/streams@0.2.0.{output-stream};
get-stdout: func() -> output-stream;
}
interface stderr {
use wasi:io/streams@0.2.0.{output-stream};
get-stderr: func() -> output-stream;
}
interface terminal-input {
resource terminal-input;
}
interface terminal-output {
resource terminal-output;
}
interface terminal-stdin {
use terminal-input.{terminal-input};
get-terminal-stdin: func() -> option<terminal-input>;
}
interface terminal-stdout {
use terminal-output.{terminal-output};
get-terminal-stdout: func() -> option<terminal-output>;
}
interface terminal-stderr {
use terminal-output.{terminal-output};
get-terminal-stderr: func() -> option<terminal-output>;
}
}
package wasi:clocks@0.2.0 {
interface monotonic-clock {
use wasi:io/poll@0.2.0.{pollable};
type instant = u64;
type duration = u64;
now: func() -> instant;
resolution: func() -> duration;
subscribe-instant: func(when: instant) -> pollable;
subscribe-duration: func(when: duration) -> pollable;
}
interface wall-clock {
record datetime {
seconds: u64,
nanoseconds: u32,
}
now: func() -> datetime;
resolution: func() -> datetime;
export wasi:http/incoming-handler@0.2.0;
export wasmcloud:messaging/handler@0.2.0;
}
}
@ -282,12 +213,17 @@ package wasi:filesystem@0.2.0 {
}
package wasi:http@0.2.0 {
/// This interface defines all of the types and methods for implementing
/// HTTP Requests and Responses, both incoming and outgoing, as well as
/// their headers, trailers, and bodies.
interface types {
use wasi:clocks/monotonic-clock@0.2.0.{duration};
use wasi:io/streams@0.2.0.{input-stream};
use wasi:io/streams@0.2.0.{output-stream};
use wasi:io/error@0.2.0.{error as io-error};
use wasi:io/poll@0.2.0.{pollable};
/// This type corresponds to HTTP standard Methods.
variant method {
get,
head,
@ -300,19 +236,30 @@ package wasi:http@0.2.0 {
patch,
other(string),
}
/// This type corresponds to HTTP standard Related Schemes.
variant scheme { HTTP, HTTPS, other(string) }
/// Defines the case payload type for `DNS-error` above:
record DNS-error-payload {
rcode: option<string>,
info-code: option<u16>,
}
/// Defines the case payload type for `TLS-alert-received` above:
record TLS-alert-received-payload {
alert-id: option<u8>,
alert-message: option<string>,
}
/// Defines the case payload type for `HTTP-response-{header,trailer}-size` above:
record field-size-payload {
field-name: option<string>,
field-size: option<u32>,
}
/// These cases are inspired by the IANA HTTP Proxy Error Types:
/// https://www.iana.org/assignments/http-proxy-status/http-proxy-status.xhtml#table-http-proxy-error-types
variant error-code {
DNS-timeout,
DNS-error(DNS-error-payload),
@ -352,102 +299,568 @@ package wasi:http@0.2.0 {
HTTP-protocol-error,
loop-detected,
configuration-error,
/// This is a catch-all error for anything that doesn't fit cleanly into a
/// more specific case. It also includes an optional string for an
/// unstructured description of the error. Users should not depend on the
/// string for diagnosing errors, as it's not required to be consistent
/// between implementations.
internal-error(option<string>),
}
/// This type enumerates the different kinds of errors that may occur when
/// setting or appending to a `fields` resource.
variant header-error {
/// This error indicates that a `field-key` or `field-value` was
/// syntactically invalid when used with an operation that sets headers in a
/// `fields`.
invalid-syntax,
/// This error indicates that a forbidden `field-key` was used when trying
/// to set a header in a `fields`.
forbidden,
/// This error indicates that the operation on the `fields` was not
/// permitted because the fields are immutable.
immutable,
}
/// Field keys are always strings.
type field-key = string;
/// Field values should always be ASCII strings. However, in
/// reality, HTTP implementations often have to interpret malformed values,
/// so they are provided as a list of bytes.
type field-value = list<u8>;
/// This following block defines the `fields` resource which corresponds to
/// HTTP standard Fields. Fields are a common representation used for both
/// Headers and Trailers.
///
/// A `fields` may be mutable or immutable. A `fields` created using the
/// constructor, `from-list`, or `clone` will be mutable, but a `fields`
/// resource given by other means (including, but not limited to,
/// `incoming-request.headers`, `outgoing-request.headers`) might be be
/// immutable. In an immutable fields, the `set`, `append`, and `delete`
/// operations will fail with `header-error.immutable`.
resource fields {
/// Construct an empty HTTP Fields.
///
/// The resulting `fields` is mutable.
constructor();
/// Append a value for a key. Does not change or delete any existing
/// values for that key.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
append: func(name: field-key, value: field-value) -> result<_, header-error>;
/// Make a deep copy of the Fields. Equivelant in behavior to calling the
/// `fields` constructor on the return value of `entries`. The resulting
/// `fields` is mutable.
clone: func() -> fields;
/// Delete all values for a key. Does nothing if no values for the key
/// exist.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
delete: func(name: field-key) -> result<_, header-error>;
/// Retrieve the full set of keys and values in the Fields. Like the
/// constructor, the list represents each key-value pair.
///
/// The outer list represents each key-value pair in the Fields. Keys
/// which have multiple values are represented by multiple entries in this
/// list with the same key.
entries: func() -> list<tuple<field-key, field-value>>;
/// Get all of the values corresponding to a key. If the key is not present
/// in this `fields`, an empty list is returned. However, if the key is
/// present but empty, this is represented by a list with one or more
/// empty field-values present.
get: func(name: field-key) -> list<field-value>;
/// Returns `true` when the key is present in this `fields`. If the key is
/// syntactically invalid, `false` is returned.
has: func(name: field-key) -> bool;
/// Set all of the values for a key. Clears any existing values for that
/// key, if they have been set.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
set: func(name: field-key, value: list<field-value>) -> result<_, header-error>;
/// Construct an HTTP Fields.
///
/// The resulting `fields` is mutable.
///
/// The list represents each key-value pair in the Fields. Keys
/// which have multiple values are represented by multiple entries in this
/// list with the same key.
///
/// The tuple is a pair of the field key, represented as a string, and
/// Value, represented as a list of bytes. In a valid Fields, all keys
/// and values are valid UTF-8 strings. However, values are not always
/// well-formed, so they are represented as a raw list of bytes.
///
/// An error result will be returned if any header or value was
/// syntactically invalid, or if a header was forbidden.
from-list: static func(entries: list<tuple<field-key, field-value>>) -> result<fields, header-error>;
}
/// Headers is an alias for Fields.
type headers = fields;
/// Trailers is an alias for Fields.
type trailers = fields;
/// Represents an incoming HTTP Request.
resource incoming-request {
/// Returns the authority from the request, if it was present.
authority: func() -> option<string>;
/// Gives the `incoming-body` associated with this request. Will only
/// return success at most once, and subsequent calls will return error.
consume: func() -> result<incoming-body>;
/// Get the `headers` associated with the request.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// The `headers` returned are a child resource: it must be dropped before
/// the parent `incoming-request` is dropped. Dropping this
/// `incoming-request` before all children are dropped will trap.
headers: func() -> headers;
/// Returns the method of the incoming request.
method: func() -> method;
/// Returns the path with query parameters from the request, as a string.
path-with-query: func() -> option<string>;
/// Returns the protocol scheme from the request.
scheme: func() -> option<scheme>;
}
/// Represents an outgoing HTTP Request.
resource outgoing-request {
/// Construct a new `outgoing-request` with a default `method` of `GET`, and
/// `none` values for `path-with-query`, `scheme`, and `authority`.
///
/// * `headers` is the HTTP Headers for the Request.
///
/// It is possible to construct, or manipulate with the accessor functions
/// below, an `outgoing-request` with an invalid combination of `scheme`
/// and `authority`, or `headers` which are not permitted to be sent.
/// It is the obligation of the `outgoing-handler.handle` implementation
/// to reject invalid constructions of `outgoing-request`.
constructor(headers: headers);
/// Get the HTTP Authority for the Request. A value of `none` may be used
/// with Related Schemes which do not require an Authority. The HTTP and
/// HTTPS schemes always require an authority.
authority: func() -> option<string>;
/// Returns the resource corresponding to the outgoing Body for this
/// Request.
///
/// Returns success on the first call: the `outgoing-body` resource for
/// this `outgoing-request` can be retrieved at most once. Subsequent
/// calls will return error.
body: func() -> result<outgoing-body>;
/// Get the headers associated with the Request.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// This headers resource is a child: it must be dropped before the parent
/// `outgoing-request` is dropped, or its ownership is transfered to
/// another component by e.g. `outgoing-handler.handle`.
headers: func() -> headers;
/// Get the Method for the Request.
method: func() -> method;
/// Get the combination of the HTTP Path and Query for the Request.
/// When `none`, this represents an empty Path and empty Query.
path-with-query: func() -> option<string>;
/// Get the HTTP Related Scheme for the Request. When `none`, the
/// implementation may choose an appropriate default scheme.
scheme: func() -> option<scheme>;
/// Set the HTTP Authority for the Request. A value of `none` may be used
/// with Related Schemes which do not require an Authority. The HTTP and
/// HTTPS schemes always require an authority. Fails if the string given is
/// not a syntactically valid uri authority.
set-authority: func(authority: option<string>) -> result;
/// Set the Method for the Request. Fails if the string present in a
/// `method.other` argument is not a syntactically valid method.
set-method: func(method: method) -> result;
/// Set the combination of the HTTP Path and Query for the Request.
/// When `none`, this represents an empty Path and empty Query. Fails is the
/// string given is not a syntactically valid path and query uri component.
set-path-with-query: func(path-with-query: option<string>) -> result;
/// Set the HTTP Related Scheme for the Request. When `none`, the
/// implementation may choose an appropriate default scheme. Fails if the
/// string given is not a syntactically valid uri scheme.
set-scheme: func(scheme: option<scheme>) -> result;
}
/// Parameters for making an HTTP Request. Each of these parameters is
/// currently an optional timeout applicable to the transport layer of the
/// HTTP protocol.
///
/// These timeouts are separate from any the user may use to bound a
/// blocking call to `wasi:io/poll.poll`.
resource request-options {
/// Construct a default `request-options` value.
constructor();
/// The timeout for receiving subsequent chunks of bytes in the Response
/// body stream.
between-bytes-timeout: func() -> option<duration>;
/// The timeout for the initial connect to the HTTP Server.
connect-timeout: func() -> option<duration>;
/// The timeout for receiving the first byte of the Response body.
first-byte-timeout: func() -> option<duration>;
/// Set the timeout for receiving subsequent chunks of bytes in the Response
/// body stream. An error return value indicates that this timeout is not
/// supported.
set-between-bytes-timeout: func(duration: option<duration>) -> result;
/// Set the timeout for the initial connect to the HTTP Server. An error
/// return value indicates that this timeout is not supported.
set-connect-timeout: func(duration: option<duration>) -> result;
/// Set the timeout for receiving the first byte of the Response body. An
/// error return value indicates that this timeout is not supported.
set-first-byte-timeout: func(duration: option<duration>) -> result;
}
/// Represents the ability to send an HTTP Response.
///
/// This resource is used by the `wasi:http/incoming-handler` interface to
/// allow a Response to be sent corresponding to the Request provided as the
/// other argument to `incoming-handler.handle`.
resource response-outparam {
/// Set the value of the `response-outparam` to either send a response,
/// or indicate an error.
///
/// This method consumes the `response-outparam` to ensure that it is
/// called at most once. If it is never called, the implementation
/// will respond with an error.
///
/// The user may provide an `error` to `response` to allow the
/// implementation determine how to respond with an HTTP error response.
set: static func(param: response-outparam, response: result<outgoing-response, error-code>);
}
/// This type corresponds to the HTTP standard Status Code.
type status-code = u16;
/// Represents an incoming HTTP Response.
resource incoming-response {
/// Returns the incoming body. May be called at most once. Returns error
/// if called additional times.
consume: func() -> result<incoming-body>;
/// Returns the headers from the incoming response.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// This headers resource is a child: it must be dropped before the parent
/// `incoming-response` is dropped.
headers: func() -> headers;
/// Returns the status code from the incoming response.
status: func() -> status-code;
}
/// Represents an incoming HTTP Request or Response's Body.
///
/// A body has both its contents - a stream of bytes - and a (possibly
/// empty) set of trailers, indicating that the full contents of the
/// body have been received. This resource represents the contents as
/// an `input-stream` and the delivery of trailers as a `future-trailers`,
/// and ensures that the user of this interface may only be consuming either
/// the body contents or waiting on trailers at any given time.
resource incoming-body {
/// Returns the contents of the body, as a stream of bytes.
///
/// Returns success on first call: the stream representing the contents
/// can be retrieved at most once. Subsequent calls will return error.
///
/// The returned `input-stream` resource is a child: it must be dropped
/// before the parent `incoming-body` is dropped, or consumed by
/// `incoming-body.finish`.
///
/// This invariant ensures that the implementation can determine whether
/// the user is consuming the contents of the body, waiting on the
/// `future-trailers` to be ready, or neither. This allows for network
/// backpressure is to be applied when the user is consuming the body,
/// and for that backpressure to not inhibit delivery of the trailers if
/// the user does not read the entire body.
%stream: func() -> result<input-stream>;
/// Takes ownership of `incoming-body`, and returns a `future-trailers`.
/// This function will trap if the `input-stream` child is still alive.
finish: static func(this: incoming-body) -> future-trailers;
}
/// Represents a future which may eventaully return trailers, or an error.
///
/// In the case that the incoming HTTP Request or Response did not have any
/// trailers, this future will resolve to the empty set of trailers once the
/// complete Request or Response body has been received.
resource future-trailers {
/// Returns the contents of the trailers, or an error which occured,
/// once the future is ready.
///
/// The outer `option` represents future readiness. Users can wait on this
/// `option` to become `some` using the `subscribe` method.
///
/// The outer `result` is used to retrieve the trailers or error at most
/// once. It will be success on the first call in which the outer option
/// is `some`, and error on subsequent calls.
///
/// The inner `result` represents that either the HTTP Request or Response
/// body, as well as any trailers, were received successfully, or that an
/// error occured receiving them. The optional `trailers` indicates whether
/// or not trailers were present in the body.
///
/// When some `trailers` are returned by this method, the `trailers`
/// resource is immutable, and a child. Use of the `set`, `append`, or
/// `delete` methods will return an error, and the resource must be
/// dropped before the parent `future-trailers` is dropped.
get: func() -> option<result<result<option<trailers>, error-code>>>;
/// Returns a pollable which becomes ready when either the trailers have
/// been received, or an error has occured. When this pollable is ready,
/// the `get` method will return `some`.
subscribe: func() -> pollable;
}
/// Represents an outgoing HTTP Response.
resource outgoing-response {
/// Construct an `outgoing-response`, with a default `status-code` of `200`.
/// If a different `status-code` is needed, it must be set via the
/// `set-status-code` method.
///
/// * `headers` is the HTTP Headers for the Response.
constructor(headers: headers);
/// Returns the resource corresponding to the outgoing Body for this Response.
///
/// Returns success on the first call: the `outgoing-body` resource for
/// this `outgoing-response` can be retrieved at most once. Subsequent
/// calls will return error.
body: func() -> result<outgoing-body>;
/// Get the headers associated with the Request.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// This headers resource is a child: it must be dropped before the parent
/// `outgoing-request` is dropped, or its ownership is transfered to
/// another component by e.g. `outgoing-handler.handle`.
headers: func() -> headers;
/// Set the HTTP Status Code for the Response. Fails if the status-code
/// given is not a valid http status code.
set-status-code: func(status-code: status-code) -> result;
/// Get the HTTP Status Code for the Response.
status-code: func() -> status-code;
}
/// Represents an outgoing HTTP Request or Response's Body.
///
/// A body has both its contents - a stream of bytes - and a (possibly
/// empty) set of trailers, inducating the full contents of the body
/// have been sent. This resource represents the contents as an
/// `output-stream` child resource, and the completion of the body (with
/// optional trailers) with a static function that consumes the
/// `outgoing-body` resource, and ensures that the user of this interface
/// may not write to the body contents after the body has been finished.
///
/// If the user code drops this resource, as opposed to calling the static
/// method `finish`, the implementation should treat the body as incomplete,
/// and that an error has occured. The implementation should propogate this
/// error to the HTTP protocol by whatever means it has available,
/// including: corrupting the body on the wire, aborting the associated
/// Request, or sending a late status code for the Response.
resource outgoing-body {
/// Returns a stream for writing the body contents.
///
/// The returned `output-stream` is a child resource: it must be dropped
/// before the parent `outgoing-body` resource is dropped (or finished),
/// otherwise the `outgoing-body` drop or `finish` will trap.
///
/// Returns success on the first call: the `output-stream` resource for
/// this `outgoing-body` may be retrieved at most once. Subsequent calls
/// will return error.
write: func() -> result<output-stream>;
/// Finalize an outgoing body, optionally providing trailers. This must be
/// called to signal that the response is complete. If the `outgoing-body`
/// is dropped without calling `outgoing-body.finalize`, the implementation
/// should treat the body as corrupted.
///
/// Fails if the body's `outgoing-request` or `outgoing-response` was
/// constructed with a Content-Length header, and the contents written
/// to the body (via `write`) does not match the value given in the
/// Content-Length.
finish: static func(this: outgoing-body, trailers: option<trailers>) -> result<_, error-code>;
}
/// Represents a future which may eventaully return an incoming HTTP
/// Response, or an error.
///
/// This resource is returned by the `wasi:http/outgoing-handler` interface to
/// provide the HTTP Response corresponding to the sent Request.
resource future-incoming-response {
/// Returns the incoming HTTP Response, or an error, once one is ready.
///
/// The outer `option` represents future readiness. Users can wait on this
/// `option` to become `some` using the `subscribe` method.
///
/// The outer `result` is used to retrieve the response or error at most
/// once. It will be success on the first call in which the outer option
/// is `some`, and error on subsequent calls.
///
/// The inner `result` represents that either the incoming HTTP Response
/// status and headers have recieved successfully, or that an error
/// occured. Errors may also occur while consuming the response body,
/// but those will be reported by the `incoming-body` and its
/// `output-stream` child.
get: func() -> option<result<result<incoming-response, error-code>>>;
/// Returns a pollable which becomes ready when either the Response has
/// been received, or an error has occured. When this pollable is ready,
/// the `get` method will return `some`.
subscribe: func() -> pollable;
}
/// Attempts to extract a http-related `error` from the wasi:io `error`
/// provided.
///
/// Stream operations which return
/// `wasi:io/stream/stream-error::last-operation-failed` have a payload of
/// type `wasi:io/error/error` with more information about the operation
/// that failed. This payload can be passed through to this function to see
/// if there's http-related information about the error to return.
///
/// Note that this function is fallible because not all io-errors are
/// http-related errors.
http-error-code: func(err: borrow<io-error>) -> option<error-code>;
}
/// This interface defines a handler of incoming HTTP Requests. It should
/// be exported by components which can respond to HTTP Requests.
interface incoming-handler {
use types.{incoming-request};
use types.{response-outparam};
/// This function is invoked with an incoming HTTP Request, and a resource
/// `response-outparam` which provides the capability to reply with an HTTP
/// Response. The response is sent by calling the `response-outparam.set`
/// method, which allows execution to continue after the response has been
/// sent. This enables both streaming to the response body, and performing other
/// work.
///
/// The implementor of this function must write a response to the
/// `response-outparam` before returning, or else the caller will respond
/// with an error on its behalf.
handle: func(request: incoming-request, response-out: response-outparam);
}
/// This interface defines a handler of outgoing HTTP Requests. It should be
/// imported by components which wish to make HTTP Requests.
interface outgoing-handler {
use types.{outgoing-request};
use types.{request-options};
use types.{future-incoming-response};
use types.{error-code};
/// This function is invoked with an outgoing HTTP Request, and it returns
/// a resource `future-incoming-response` which represents an HTTP Response
/// which may arrive in the future.
///
/// The `options` argument accepts optional parameters for the HTTP
/// protocol's transport layer.
///
/// This function may return an error if the `outgoing-request` is invalid
/// or not allowed to be made. Otherwise, protocol errors are reported
/// through the `future-incoming-response`.
handle: func(request: outgoing-request, options: option<request-options>) -> result<future-incoming-response, error-code>;
}
}
package wasi:cli@0.2.0 {
interface stdout {
use wasi:io/streams@0.2.0.{output-stream};
get-stdout: func() -> output-stream;
}
interface stderr {
use wasi:io/streams@0.2.0.{output-stream};
get-stderr: func() -> output-stream;
}
interface stdin {
use wasi:io/streams@0.2.0.{input-stream};
get-stdin: func() -> input-stream;
}
interface environment {
get-environment: func() -> list<tuple<string, string>>;
get-arguments: func() -> list<string>;
initial-cwd: func() -> option<string>;
}
interface exit {
exit: func(status: result);
}
interface terminal-input {
resource terminal-input;
}
interface terminal-output {
resource terminal-output;
}
interface terminal-stdin {
use terminal-input.{terminal-input};
get-terminal-stdin: func() -> option<terminal-input>;
}
interface terminal-stdout {
use terminal-output.{terminal-output};
get-terminal-stdout: func() -> option<terminal-output>;
}
interface terminal-stderr {
use terminal-output.{terminal-output};
get-terminal-stderr: func() -> option<terminal-output>;
}
}
package wasi:io@0.2.0 {
interface poll {
resource pollable {
@ -706,6 +1119,27 @@ package wasi:sockets@0.2.0 {
}
}
package wasi:clocks@0.2.0 {
interface monotonic-clock {
use wasi:io/poll@0.2.0.{pollable};
type instant = u64;
type duration = u64;
now: func() -> instant;
resolution: func() -> duration;
subscribe-instant: func(when: instant) -> pollable;
subscribe-duration: func(when: duration) -> pollable;
}
interface wall-clock {
record datetime {
seconds: u64,
nanoseconds: u32,
}
now: func() -> datetime;
resolution: func() -> datetime;
}
}
package wasmcloud:bus@1.0.0 {
interface lattice {
resource call-target-interface {
@ -726,6 +1160,13 @@ package wasmcloud:messaging@0.2.0 {
}
}
interface handler {
use types.{broker-message};
/// Callback handled to invoke a function when a message is received from a subscription
handle-message: func(msg: broker-message) -> result<_, string>;
}
interface consumer {
use types.{broker-message};

View File

@ -0,0 +1,22 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
package handler
import (
"gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasmcloud/messaging/types"
"github.com/bytecodealliance/wasm-tools-go/cm"
)
func lift_OptionString(f0 uint32, f1 *uint8, f2 uint32) (v cm.Option[string]) {
if f0 == 0 {
return
}
return (cm.Option[string])(cm.Some[string](cm.LiftString[string]((*uint8)(f1), (uint32)(f2))))
}
func lift_BrokerMessage(f0 *uint8, f1 uint32, f2 *uint8, f3 uint32, f4 uint32, f5 *uint8, f6 uint32) (v types.BrokerMessage) {
v.Subject = cm.LiftString[string](f0, f1)
v.Body = cm.LiftList[cm.List[uint8]](f2, f3)
v.ReplyTo = lift_OptionString(f4, f5, f6)
return
}

View File

@ -0,0 +1,3 @@
// This file exists for testing this package without WebAssembly,
// allowing empty function bodies with a //go:wasmimport directive.
// See https://pkg.go.dev/cmd/compile for more information.

View File

@ -0,0 +1,17 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
package handler
import (
"github.com/bytecodealliance/wasm-tools-go/cm"
)
// Exports represents the caller-defined exports from "wasmcloud:messaging/handler@0.2.0".
var Exports struct {
// HandleMessage represents the caller-defined, exported function "handle-message".
//
// Callback handled to invoke a function when a message is received from a subscription
//
// handle-message: func(msg: broker-message) -> result<_, string>
HandleMessage func(msg BrokerMessage) (result cm.Result[string, struct{}, string])
}

View File

@ -0,0 +1,18 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
package handler
import (
"github.com/bytecodealliance/wasm-tools-go/cm"
)
// This file contains wasmimport and wasmexport declarations for "wasmcloud:messaging@0.2.0".
//go:wasmexport wasmcloud:messaging/handler@0.2.0#handle-message
//export wasmcloud:messaging/handler@0.2.0#handle-message
func wasmexport_HandleMessage(msg0 *uint8, msg1 uint32, msg2 *uint8, msg3 uint32, msg4 uint32, msg5 *uint8, msg6 uint32) (result *cm.Result[string, struct{}, string]) {
msg := lift_BrokerMessage((*uint8)(msg0), (uint32)(msg1), (*uint8)(msg2), (uint32)(msg3), (uint32)(msg4), (*uint8)(msg5), (uint32)(msg6))
result_ := Exports.HandleMessage(msg)
result = &result_
return
}

View File

@ -0,0 +1,13 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
// Package handler represents the exported interface "wasmcloud:messaging/handler@0.2.0".
package handler
import (
"gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasmcloud/messaging/types"
)
// BrokerMessage represents the type alias "wasmcloud:messaging/handler@0.2.0#broker-message".
//
// See [types.BrokerMessage] for more information.
type BrokerMessage = types.BrokerMessage

2
go.mod
View File

@ -17,7 +17,7 @@ require (
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/urfave/cli/v3 v3.0.0-beta1 // indirect
go.bytecodealliance.org v0.4.1 // indirect
go.bytecodealliance.org v0.4.0 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect

104
go.sum
View File

@ -1,52 +1,52 @@
github.com/bytecodealliance/wasm-tools-go v0.3.2 h1:LKni9PS8yCG5/A79L8tcTKthgf7WN5RZD83W1m6wEE0=
github.com/bytecodealliance/wasm-tools-go v0.3.2/go.mod h1:fdysX1+SiPxcIhdpg8TLhoxz23k28/5cQ0/L9J4mgig=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/olareg/olareg v0.1.1 h1:Ui7q93zjcoF+U9U71sgqgZWByDoZOpqHitUXEu2xV+g=
github.com/olareg/olareg v0.1.1/go.mod h1:w8NP4SWrHHtxsFaUiv1lnCnYPm4sN1seCd2h7FK/dc0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/regclient/regclient v0.8.0 h1:xNAMDlADcyMvFAlGXoqDOxlSUBG4mqWBFgjQqVTP8Og=
github.com/regclient/regclient v0.8.0/go.mod h1:h9+Y6dBvqBkdlrj6EIhbTOv0xUuIFl7CdI1bZvEB42g=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
go.bytecodealliance.org v0.4.1 h1:Y3Nnz+C061i9Hw4qQlSkZTg3IBTsTLC92+sdh4xCADQ=
go.bytecodealliance.org v0.4.1/go.mod h1:jxAxqtTxs+6Q2q6bQnWa/lF+Q+2/LkdbqIgNJYxEmFA=
go.wasmcloud.dev/component v0.0.5 h1:z9+fq1CJKm/yom33ctd5wfo8TVunm5IaI7EJdY2i9hk=
go.wasmcloud.dev/component v0.0.5/go.mod h1:PvVHQ7Xp8D9kZnVB3fm8lqWAcC6Yxd7CI/snXZUAG8E=
go.wasmcloud.dev/wadge v0.7.0 h1:eUt0jODh6xQ5HEof1PFSgDp+evrNs+lD1LYCYeRR2Cg=
go.wasmcloud.dev/wadge v0.7.0/go.mod h1:SMnPSWZFTkXyUX0GJ11mcdc7ZoMITtbAlPLlpvGJd4M=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
github.com/bytecodealliance/wasm-tools-go v0.3.2 h1:LKni9PS8yCG5/A79L8tcTKthgf7WN5RZD83W1m6wEE0=
github.com/bytecodealliance/wasm-tools-go v0.3.2/go.mod h1:fdysX1+SiPxcIhdpg8TLhoxz23k28/5cQ0/L9J4mgig=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/olareg/olareg v0.1.1 h1:Ui7q93zjcoF+U9U71sgqgZWByDoZOpqHitUXEu2xV+g=
github.com/olareg/olareg v0.1.1/go.mod h1:w8NP4SWrHHtxsFaUiv1lnCnYPm4sN1seCd2h7FK/dc0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/regclient/regclient v0.8.0 h1:xNAMDlADcyMvFAlGXoqDOxlSUBG4mqWBFgjQqVTP8Og=
github.com/regclient/regclient v0.8.0/go.mod h1:h9+Y6dBvqBkdlrj6EIhbTOv0xUuIFl7CdI1bZvEB42g=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
go.bytecodealliance.org v0.4.0 h1:SRwgZIcXR54AmbJg9Y3AMgDlZlvD8dffteBYW+nCD3k=
go.bytecodealliance.org v0.4.0/go.mod h1:hkdjfgQ/bFZYUucnm9cn0Q8/SHO3iT0rzskYlkV4Jy0=
go.wasmcloud.dev/component v0.0.5 h1:z9+fq1CJKm/yom33ctd5wfo8TVunm5IaI7EJdY2i9hk=
go.wasmcloud.dev/component v0.0.5/go.mod h1:PvVHQ7Xp8D9kZnVB3fm8lqWAcC6Yxd7CI/snXZUAG8E=
go.wasmcloud.dev/wadge v0.7.0 h1:eUt0jODh6xQ5HEof1PFSgDp+evrNs+lD1LYCYeRR2Cg=
go.wasmcloud.dev/wadge v0.7.0/go.mod h1:SMnPSWZFTkXyUX0GJ11mcdc7ZoMITtbAlPLlpvGJd4M=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

17
main.go
View File

@ -2,10 +2,25 @@
package main
import (
"net/http"
"fmt"
"go.wasmcloud.dev/component/net/wasihttp"
"gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasmcloud/messaging/handler"
)
func init() {
loop()
wasihttp.HandleFunc(handleRequest)
handler.Exports.HandleMessage = handleMessage
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
// get body as string
handleHttp(r.FormValue("data"))
// send response
fmt.Fprintf(w, "Message sent!\n")
}
// Since we don't run this program like a CLI, the `main` function is empty. Instead,

View File

@ -1,54 +0,0 @@
//go:generate go run go.wasmcloud.dev/wadge/cmd/wadge-bindgen-go
package main
import (
"bytes"
"io"
"log"
"log/slog"
"net/http"
"os"
"testing"
incominghandler "go.wasmcloud.dev/component/gen/wasi/http/incoming-handler"
"go.wasmcloud.dev/wadge"
"go.wasmcloud.dev/wadge/wadgehttp"
)
func init() {
log.SetFlags(0)
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
Level: slog.LevelDebug, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
if a.Key == slog.TimeKey {
return slog.Attr{}
}
return a
},
})))
}
func TestIncomingHandler(t *testing.T) {
wadge.RunTest(t, func() {
req, err := http.NewRequest("", "/", nil)
if err != nil {
t.Fatalf("failed to create new HTTP request: %s", err)
}
resp, err := wadgehttp.HandleIncomingRequest(incominghandler.Exports.Handle, req)
if err != nil {
t.Fatalf("failed to handle incoming HTTP request: %s", err)
}
if want, got := http.StatusOK, resp.StatusCode; want != got {
t.Fatalf("unexpected status code: want %d, got %d", want, got)
}
buf, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatalf("failed to read HTTP response body: %s", err)
}
defer resp.Body.Close()
if want, got := []byte("Hello from Go!\n"), buf; !bytes.Equal(want, got) {
t.Fatalf("unexpected response body: want %q, got %q", want, got)
}
})
}

View File

@ -6,7 +6,6 @@ import (
"gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasmcloud/messaging/types"
logger "gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasi/logging/logging"
//config "gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasi/config/runtime"
"time"
)
type messagingConsumerAdapter struct {
@ -18,42 +17,49 @@ var messagingConsumer = &messagingConsumerAdapter{
Publish: consumer.Publish,
}
func loop() cm.Result[string, struct{}, string] {
func handleHttp(httpData string) {
// TODO implement the logic to get the destination topic from the config
// dest_topic := config.GetAll()
dest_topic := "test.reply"
counter := 0
dest_topic := "streaming"
// TASK
for {
// generate random message
data := []byte(httpData)
// generate random message
data := []byte("Hello, World! " + string(counter))
// Send reply
reply := types.BrokerMessage{
Subject: dest_topic,
Body: cm.ToList(data),
ReplyTo: cm.None[string](),
}
// Send reply
reply := types.BrokerMessage{
Subject: dest_topic,
Body: cm.ToList(data),
ReplyTo: cm.None[string](),
}
res := messagingConsumer.Publish(reply)
if res.IsErr() {
logger.Log(logger.LevelError, "MessageHandler", "Failed to send reply, error: " + *res.Err())
return res
}
res := messagingConsumer.Publish(reply)
counter++
if res.IsErr() {
logger.Log(logger.LevelError, "MessageHandler", "Failed to send reply, error: " + *res.Err())
}
if counter == 1000 {
break
}
}
// sleep for 1 second
time.Sleep(1 * time.Second)
func handleMessage(msg types.BrokerMessage) cm.Result[string, struct{}, string] {
logger.Log(logger.LevelInfo,"MessageHandler", "Received message on subject" + msg.Subject)
// TODO implement the logic to get the destination topic from the config
// dest_topic := config.GetAll()
dest_topic := "streaming"
// Send reply
reply := types.BrokerMessage{
Subject: dest_topic,
Body: msg.Body,
ReplyTo: cm.None[string](),
}
res := messagingConsumer.Publish(reply)
if res.IsErr() {
logger.Log(logger.LevelError, "MessageHandler", "Failed to send reply, error: " + *res.Err())
return res
}
return cm.OK[cm.Result[string, struct{}, string]](struct{}{})
}

View File

@ -3,32 +3,36 @@ kind: Application
metadata:
name: go-data-producer
annotations:
description: 'HTTP hello world demo in Golang (TinyGo), using the WebAssembly Component Model and WebAssembly Interfaces Types (WIT)'
wasmcloud.dev/authors: wasmCloud team
wasmcloud.dev/source-url: https://github.com/wasmCloud/wasmCloud/blob/main/examples/golang/components/http-hello-world/wadm.yaml
wasmcloud.dev/readme-md-url: https://github.com/wasmCloud/wasmCloud/blob/main/examples/golang/components/http-hello-world/README.md
wasmcloud.dev/homepage: https://github.com/wasmCloud/wasmCloud/tree/main/examples/golang/components/http-hello-world
description: 'Data producer using NATS topic in Golang (TinyGo), using the WebAssembly Component Model and WebAssembly Interfaces Types (WIT)'
wasmcloud.dev/authors: Lorenzo Venerandi
wasmcloud.dev/source-url: https://gitea.rebus.ninja/lore/wasm-nats-producer-client.git/wadm.yaml
wasmcloud.dev/readme-md-url: https://gitea.rebus.ninja/lore/wasm-nats-producer-client.git/README.md
wasmcloud.dev/homepage: https://gitea.rebus.ninja/lore/wasm-nats-producer-client.git
wasmcloud.dev/categories: |
http,outgoing-http,http-server,tinygo,golang,example
data-producer,nats-client,tinygo,golang
spec:
components:
- name: echo
- name: go-data-producer
type: component
properties:
# To use the locally compiled code in this folder, use the line below instead after running `wash build`:
# image: file://./build/echo_messaging_s.wasm
image: gitea.rebus.ninja/lore/go-nats-client:1.0.1
id: echo
config:
- name: nats-topic
properties:
dest-topic: wasmcloud.echo.reply
image: gitea.rebus.ninja/lore/wasm-nats-producer-client:1.0.3
id: producer
# config:
# - name: nats-topic
# properties:
# dest-topic: wasmcloud.echo.reply
traits:
# Govern the spread/scheduling of the component
- type: spreadscaler
properties:
instances: 1
spread:
- name: cloud
weight: 0
requirements:
host-type: cloud
- name: edge
weight: 100
requirements:
@ -63,10 +67,54 @@ spec:
#
# Here we link the `nats` provider (the "source"), to the `echo` component (the "target"),
# so that so the provider can deliver messages to the component (by invoking the wasmcloud:messaging/handler interface) .
- type: link
properties:
target: go-data-producer
namespace: wasmcloud
package: messaging
interfaces: [handler]
source_config:
- name: simple-subscription
properties:
subscriptions: producer
- type: spreadscaler
properties:
instances: 1
spread:
- name: cloud
weight: 0
requirements:
host-type: cloud
- name: edge
weight: 100
requirements:
host-type: edge
- name: httpserver
type: capability
properties:
image: ghcr.io/wasmcloud/http-server:0.23.2
traits:
# Link to Echo, and inform it to listen on port 8000
# on the local machine
- type: link
properties:
target: go-data-producer
namespace: wasmcloud
package: http
interfaces: [incoming-handler]
source_config:
- name: default-http
properties:
address: 0.0.0.0:8000
- type: spreadscaler
properties:
instances: 1
spread:
- name: cloud
weight: 0
requirements:
host-type: cloud
- name: edge
weight: 100
requirements:
host-type: edge

View File

@ -11,6 +11,15 @@ requirement = "=0.2.0-draft"
version = "0.2.0-draft"
digest = "sha256:aa2d36d0843999edad80a13bf22f4529277f7b6012429f8a5d1f9499f3793c1a"
[[packages]]
name = "wasi:http"
registry = "wasi.dev"
[[packages.versions]]
requirement = "=0.2.0"
version = "0.2.0"
digest = "sha256:5a568e6e2d60c1ce51220e1833cdd5b88db9f615720edc762a9b4a6f36b383bd"
[[packages]]
name = "wasi:logging"
registry = "wasi.dev"

View File

@ -1,23 +1,5 @@
package wasi:cli@0.2.0;
interface environment {
get-environment: func() -> list<tuple<string, string>>;
get-arguments: func() -> list<string>;
initial-cwd: func() -> option<string>;
}
interface exit {
exit: func(status: result);
}
interface stdin {
use wasi:io/streams@0.2.0.{input-stream};
get-stdin: func() -> input-stream;
}
interface stdout {
use wasi:io/streams@0.2.0.{output-stream};
@ -30,6 +12,24 @@ interface stderr {
get-stderr: func() -> output-stream;
}
interface stdin {
use wasi:io/streams@0.2.0.{input-stream};
get-stdin: func() -> input-stream;
}
interface environment {
get-environment: func() -> list<tuple<string, string>>;
get-arguments: func() -> list<string>;
initial-cwd: func() -> option<string>;
}
interface exit {
exit: func(status: result);
}
interface terminal-input {
resource terminal-input;
}

View File

@ -1,11 +1,15 @@
package wasi:http@0.2.0;
/// This interface defines all of the types and methods for implementing
/// HTTP Requests and Responses, both incoming and outgoing, as well as
/// their headers, trailers, and bodies.
interface types {
use wasi:clocks/monotonic-clock@0.2.0.{duration};
use wasi:io/streams@0.2.0.{input-stream, output-stream};
use wasi:io/error@0.2.0.{error as io-error};
use wasi:io/poll@0.2.0.{pollable};
/// This type corresponds to HTTP standard Methods.
variant method {
get,
head,
@ -19,27 +23,33 @@ interface types {
other(string),
}
/// This type corresponds to HTTP standard Related Schemes.
variant scheme {
HTTP,
HTTPS,
other(string),
}
/// Defines the case payload type for `DNS-error` above:
record DNS-error-payload {
rcode: option<string>,
info-code: option<u16>,
}
/// Defines the case payload type for `TLS-alert-received` above:
record TLS-alert-received-payload {
alert-id: option<u8>,
alert-message: option<string>,
}
/// Defines the case payload type for `HTTP-response-{header,trailer}-size` above:
record field-size-payload {
field-name: option<string>,
field-size: option<u32>,
}
/// These cases are inspired by the IANA HTTP Proxy Error Types:
/// https://www.iana.org/assignments/http-proxy-status/http-proxy-status.xhtml#table-http-proxy-error-types
variant error-code {
DNS-timeout,
DNS-error(DNS-error-payload),
@ -79,120 +89,483 @@ interface types {
HTTP-protocol-error,
loop-detected,
configuration-error,
/// This is a catch-all error for anything that doesn't fit cleanly into a
/// more specific case. It also includes an optional string for an
/// unstructured description of the error. Users should not depend on the
/// string for diagnosing errors, as it's not required to be consistent
/// between implementations.
internal-error(option<string>),
}
/// This type enumerates the different kinds of errors that may occur when
/// setting or appending to a `fields` resource.
variant header-error {
/// This error indicates that a `field-key` or `field-value` was
/// syntactically invalid when used with an operation that sets headers in a
/// `fields`.
invalid-syntax,
/// This error indicates that a forbidden `field-key` was used when trying
/// to set a header in a `fields`.
forbidden,
/// This error indicates that the operation on the `fields` was not
/// permitted because the fields are immutable.
immutable,
}
/// Field keys are always strings.
type field-key = string;
/// Field values should always be ASCII strings. However, in
/// reality, HTTP implementations often have to interpret malformed values,
/// so they are provided as a list of bytes.
type field-value = list<u8>;
/// This following block defines the `fields` resource which corresponds to
/// HTTP standard Fields. Fields are a common representation used for both
/// Headers and Trailers.
///
/// A `fields` may be mutable or immutable. A `fields` created using the
/// constructor, `from-list`, or `clone` will be mutable, but a `fields`
/// resource given by other means (including, but not limited to,
/// `incoming-request.headers`, `outgoing-request.headers`) might be be
/// immutable. In an immutable fields, the `set`, `append`, and `delete`
/// operations will fail with `header-error.immutable`.
resource fields {
/// Construct an empty HTTP Fields.
///
/// The resulting `fields` is mutable.
constructor();
/// Construct an HTTP Fields.
///
/// The resulting `fields` is mutable.
///
/// The list represents each key-value pair in the Fields. Keys
/// which have multiple values are represented by multiple entries in this
/// list with the same key.
///
/// The tuple is a pair of the field key, represented as a string, and
/// Value, represented as a list of bytes. In a valid Fields, all keys
/// and values are valid UTF-8 strings. However, values are not always
/// well-formed, so they are represented as a raw list of bytes.
///
/// An error result will be returned if any header or value was
/// syntactically invalid, or if a header was forbidden.
from-list: static func(entries: list<tuple<field-key, field-value>>) -> result<fields, header-error>;
/// Get all of the values corresponding to a key. If the key is not present
/// in this `fields`, an empty list is returned. However, if the key is
/// present but empty, this is represented by a list with one or more
/// empty field-values present.
get: func(name: field-key) -> list<field-value>;
/// Returns `true` when the key is present in this `fields`. If the key is
/// syntactically invalid, `false` is returned.
has: func(name: field-key) -> bool;
/// Set all of the values for a key. Clears any existing values for that
/// key, if they have been set.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
set: func(name: field-key, value: list<field-value>) -> result<_, header-error>;
/// Delete all values for a key. Does nothing if no values for the key
/// exist.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
delete: func(name: field-key) -> result<_, header-error>;
/// Append a value for a key. Does not change or delete any existing
/// values for that key.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
append: func(name: field-key, value: field-value) -> result<_, header-error>;
/// Retrieve the full set of keys and values in the Fields. Like the
/// constructor, the list represents each key-value pair.
///
/// The outer list represents each key-value pair in the Fields. Keys
/// which have multiple values are represented by multiple entries in this
/// list with the same key.
entries: func() -> list<tuple<field-key, field-value>>;
/// Make a deep copy of the Fields. Equivelant in behavior to calling the
/// `fields` constructor on the return value of `entries`. The resulting
/// `fields` is mutable.
clone: func() -> fields;
}
/// Headers is an alias for Fields.
type headers = fields;
/// Trailers is an alias for Fields.
type trailers = fields;
/// Represents an incoming HTTP Request.
resource incoming-request {
/// Returns the method of the incoming request.
method: func() -> method;
/// Returns the path with query parameters from the request, as a string.
path-with-query: func() -> option<string>;
/// Returns the protocol scheme from the request.
scheme: func() -> option<scheme>;
/// Returns the authority from the request, if it was present.
authority: func() -> option<string>;
/// Get the `headers` associated with the request.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// The `headers` returned are a child resource: it must be dropped before
/// the parent `incoming-request` is dropped. Dropping this
/// `incoming-request` before all children are dropped will trap.
headers: func() -> headers;
/// Gives the `incoming-body` associated with this request. Will only
/// return success at most once, and subsequent calls will return error.
consume: func() -> result<incoming-body>;
}
/// Represents an outgoing HTTP Request.
resource outgoing-request {
/// Construct a new `outgoing-request` with a default `method` of `GET`, and
/// `none` values for `path-with-query`, `scheme`, and `authority`.
///
/// * `headers` is the HTTP Headers for the Request.
///
/// It is possible to construct, or manipulate with the accessor functions
/// below, an `outgoing-request` with an invalid combination of `scheme`
/// and `authority`, or `headers` which are not permitted to be sent.
/// It is the obligation of the `outgoing-handler.handle` implementation
/// to reject invalid constructions of `outgoing-request`.
constructor(headers: headers);
/// Returns the resource corresponding to the outgoing Body for this
/// Request.
///
/// Returns success on the first call: the `outgoing-body` resource for
/// this `outgoing-request` can be retrieved at most once. Subsequent
/// calls will return error.
body: func() -> result<outgoing-body>;
/// Get the Method for the Request.
method: func() -> method;
/// Set the Method for the Request. Fails if the string present in a
/// `method.other` argument is not a syntactically valid method.
set-method: func(method: method) -> result;
/// Get the combination of the HTTP Path and Query for the Request.
/// When `none`, this represents an empty Path and empty Query.
path-with-query: func() -> option<string>;
/// Set the combination of the HTTP Path and Query for the Request.
/// When `none`, this represents an empty Path and empty Query. Fails is the
/// string given is not a syntactically valid path and query uri component.
set-path-with-query: func(path-with-query: option<string>) -> result;
/// Get the HTTP Related Scheme for the Request. When `none`, the
/// implementation may choose an appropriate default scheme.
scheme: func() -> option<scheme>;
/// Set the HTTP Related Scheme for the Request. When `none`, the
/// implementation may choose an appropriate default scheme. Fails if the
/// string given is not a syntactically valid uri scheme.
set-scheme: func(scheme: option<scheme>) -> result;
/// Get the HTTP Authority for the Request. A value of `none` may be used
/// with Related Schemes which do not require an Authority. The HTTP and
/// HTTPS schemes always require an authority.
authority: func() -> option<string>;
/// Set the HTTP Authority for the Request. A value of `none` may be used
/// with Related Schemes which do not require an Authority. The HTTP and
/// HTTPS schemes always require an authority. Fails if the string given is
/// not a syntactically valid uri authority.
set-authority: func(authority: option<string>) -> result;
/// Get the headers associated with the Request.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// This headers resource is a child: it must be dropped before the parent
/// `outgoing-request` is dropped, or its ownership is transfered to
/// another component by e.g. `outgoing-handler.handle`.
headers: func() -> headers;
}
/// Parameters for making an HTTP Request. Each of these parameters is
/// currently an optional timeout applicable to the transport layer of the
/// HTTP protocol.
///
/// These timeouts are separate from any the user may use to bound a
/// blocking call to `wasi:io/poll.poll`.
resource request-options {
/// Construct a default `request-options` value.
constructor();
/// The timeout for the initial connect to the HTTP Server.
connect-timeout: func() -> option<duration>;
/// Set the timeout for the initial connect to the HTTP Server. An error
/// return value indicates that this timeout is not supported.
set-connect-timeout: func(duration: option<duration>) -> result;
/// The timeout for receiving the first byte of the Response body.
first-byte-timeout: func() -> option<duration>;
/// Set the timeout for receiving the first byte of the Response body. An
/// error return value indicates that this timeout is not supported.
set-first-byte-timeout: func(duration: option<duration>) -> result;
/// The timeout for receiving subsequent chunks of bytes in the Response
/// body stream.
between-bytes-timeout: func() -> option<duration>;
/// Set the timeout for receiving subsequent chunks of bytes in the Response
/// body stream. An error return value indicates that this timeout is not
/// supported.
set-between-bytes-timeout: func(duration: option<duration>) -> result;
}
/// Represents the ability to send an HTTP Response.
///
/// This resource is used by the `wasi:http/incoming-handler` interface to
/// allow a Response to be sent corresponding to the Request provided as the
/// other argument to `incoming-handler.handle`.
resource response-outparam {
/// Set the value of the `response-outparam` to either send a response,
/// or indicate an error.
///
/// This method consumes the `response-outparam` to ensure that it is
/// called at most once. If it is never called, the implementation
/// will respond with an error.
///
/// The user may provide an `error` to `response` to allow the
/// implementation determine how to respond with an HTTP error response.
set: static func(param: response-outparam, response: result<outgoing-response, error-code>);
}
/// This type corresponds to the HTTP standard Status Code.
type status-code = u16;
/// Represents an incoming HTTP Response.
resource incoming-response {
/// Returns the status code from the incoming response.
status: func() -> status-code;
/// Returns the headers from the incoming response.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// This headers resource is a child: it must be dropped before the parent
/// `incoming-response` is dropped.
headers: func() -> headers;
/// Returns the incoming body. May be called at most once. Returns error
/// if called additional times.
consume: func() -> result<incoming-body>;
}
/// Represents an incoming HTTP Request or Response's Body.
///
/// A body has both its contents - a stream of bytes - and a (possibly
/// empty) set of trailers, indicating that the full contents of the
/// body have been received. This resource represents the contents as
/// an `input-stream` and the delivery of trailers as a `future-trailers`,
/// and ensures that the user of this interface may only be consuming either
/// the body contents or waiting on trailers at any given time.
resource incoming-body {
/// Returns the contents of the body, as a stream of bytes.
///
/// Returns success on first call: the stream representing the contents
/// can be retrieved at most once. Subsequent calls will return error.
///
/// The returned `input-stream` resource is a child: it must be dropped
/// before the parent `incoming-body` is dropped, or consumed by
/// `incoming-body.finish`.
///
/// This invariant ensures that the implementation can determine whether
/// the user is consuming the contents of the body, waiting on the
/// `future-trailers` to be ready, or neither. This allows for network
/// backpressure is to be applied when the user is consuming the body,
/// and for that backpressure to not inhibit delivery of the trailers if
/// the user does not read the entire body.
%stream: func() -> result<input-stream>;
/// Takes ownership of `incoming-body`, and returns a `future-trailers`.
/// This function will trap if the `input-stream` child is still alive.
finish: static func(this: incoming-body) -> future-trailers;
}
/// Represents a future which may eventaully return trailers, or an error.
///
/// In the case that the incoming HTTP Request or Response did not have any
/// trailers, this future will resolve to the empty set of trailers once the
/// complete Request or Response body has been received.
resource future-trailers {
/// Returns a pollable which becomes ready when either the trailers have
/// been received, or an error has occured. When this pollable is ready,
/// the `get` method will return `some`.
subscribe: func() -> pollable;
/// Returns the contents of the trailers, or an error which occured,
/// once the future is ready.
///
/// The outer `option` represents future readiness. Users can wait on this
/// `option` to become `some` using the `subscribe` method.
///
/// The outer `result` is used to retrieve the trailers or error at most
/// once. It will be success on the first call in which the outer option
/// is `some`, and error on subsequent calls.
///
/// The inner `result` represents that either the HTTP Request or Response
/// body, as well as any trailers, were received successfully, or that an
/// error occured receiving them. The optional `trailers` indicates whether
/// or not trailers were present in the body.
///
/// When some `trailers` are returned by this method, the `trailers`
/// resource is immutable, and a child. Use of the `set`, `append`, or
/// `delete` methods will return an error, and the resource must be
/// dropped before the parent `future-trailers` is dropped.
get: func() -> option<result<result<option<trailers>, error-code>>>;
}
/// Represents an outgoing HTTP Response.
resource outgoing-response {
/// Construct an `outgoing-response`, with a default `status-code` of `200`.
/// If a different `status-code` is needed, it must be set via the
/// `set-status-code` method.
///
/// * `headers` is the HTTP Headers for the Response.
constructor(headers: headers);
/// Get the HTTP Status Code for the Response.
status-code: func() -> status-code;
/// Set the HTTP Status Code for the Response. Fails if the status-code
/// given is not a valid http status code.
set-status-code: func(status-code: status-code) -> result;
/// Get the headers associated with the Request.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// This headers resource is a child: it must be dropped before the parent
/// `outgoing-request` is dropped, or its ownership is transfered to
/// another component by e.g. `outgoing-handler.handle`.
headers: func() -> headers;
/// Returns the resource corresponding to the outgoing Body for this Response.
///
/// Returns success on the first call: the `outgoing-body` resource for
/// this `outgoing-response` can be retrieved at most once. Subsequent
/// calls will return error.
body: func() -> result<outgoing-body>;
}
/// Represents an outgoing HTTP Request or Response's Body.
///
/// A body has both its contents - a stream of bytes - and a (possibly
/// empty) set of trailers, inducating the full contents of the body
/// have been sent. This resource represents the contents as an
/// `output-stream` child resource, and the completion of the body (with
/// optional trailers) with a static function that consumes the
/// `outgoing-body` resource, and ensures that the user of this interface
/// may not write to the body contents after the body has been finished.
///
/// If the user code drops this resource, as opposed to calling the static
/// method `finish`, the implementation should treat the body as incomplete,
/// and that an error has occured. The implementation should propogate this
/// error to the HTTP protocol by whatever means it has available,
/// including: corrupting the body on the wire, aborting the associated
/// Request, or sending a late status code for the Response.
resource outgoing-body {
/// Returns a stream for writing the body contents.
///
/// The returned `output-stream` is a child resource: it must be dropped
/// before the parent `outgoing-body` resource is dropped (or finished),
/// otherwise the `outgoing-body` drop or `finish` will trap.
///
/// Returns success on the first call: the `output-stream` resource for
/// this `outgoing-body` may be retrieved at most once. Subsequent calls
/// will return error.
write: func() -> result<output-stream>;
/// Finalize an outgoing body, optionally providing trailers. This must be
/// called to signal that the response is complete. If the `outgoing-body`
/// is dropped without calling `outgoing-body.finalize`, the implementation
/// should treat the body as corrupted.
///
/// Fails if the body's `outgoing-request` or `outgoing-response` was
/// constructed with a Content-Length header, and the contents written
/// to the body (via `write`) does not match the value given in the
/// Content-Length.
finish: static func(this: outgoing-body, trailers: option<trailers>) -> result<_, error-code>;
}
/// Represents a future which may eventaully return an incoming HTTP
/// Response, or an error.
///
/// This resource is returned by the `wasi:http/outgoing-handler` interface to
/// provide the HTTP Response corresponding to the sent Request.
resource future-incoming-response {
/// Returns a pollable which becomes ready when either the Response has
/// been received, or an error has occured. When this pollable is ready,
/// the `get` method will return `some`.
subscribe: func() -> pollable;
/// Returns the incoming HTTP Response, or an error, once one is ready.
///
/// The outer `option` represents future readiness. Users can wait on this
/// `option` to become `some` using the `subscribe` method.
///
/// The outer `result` is used to retrieve the response or error at most
/// once. It will be success on the first call in which the outer option
/// is `some`, and error on subsequent calls.
///
/// The inner `result` represents that either the incoming HTTP Response
/// status and headers have recieved successfully, or that an error
/// occured. Errors may also occur while consuming the response body,
/// but those will be reported by the `incoming-body` and its
/// `output-stream` child.
get: func() -> option<result<result<incoming-response, error-code>>>;
}
/// Attempts to extract a http-related `error` from the wasi:io `error`
/// provided.
///
/// Stream operations which return
/// `wasi:io/stream/stream-error::last-operation-failed` have a payload of
/// type `wasi:io/error/error` with more information about the operation
/// that failed. This payload can be passed through to this function to see
/// if there's http-related information about the error to return.
///
/// Note that this function is fallible because not all io-errors are
/// http-related errors.
http-error-code: func(err: borrow<io-error>) -> option<error-code>;
}
/// This interface defines a handler of incoming HTTP Requests. It should
/// be exported by components which can respond to HTTP Requests.
interface incoming-handler {
use types.{incoming-request, response-outparam};
/// This function is invoked with an incoming HTTP Request, and a resource
/// `response-outparam` which provides the capability to reply with an HTTP
/// Response. The response is sent by calling the `response-outparam.set`
/// method, which allows execution to continue after the response has been
/// sent. This enables both streaming to the response body, and performing other
/// work.
///
/// The implementor of this function must write a response to the
/// `response-outparam` before returning, or else the caller will respond
/// with an error on its behalf.
handle: func(request: incoming-request, response-out: response-outparam);
}
/// This interface defines a handler of outgoing HTTP Requests. It should be
/// imported by components which wish to make HTTP Requests.
interface outgoing-handler {
use types.{outgoing-request, request-options, future-incoming-response, error-code};
/// This function is invoked with an outgoing HTTP Request, and it returns
/// a resource `future-incoming-response` which represents an HTTP Response
/// which may arrive in the future.
///
/// The `options` argument accepts optional parameters for the HTTP
/// protocol's transport layer.
///
/// This function may return an error if the `outgoing-request` is invalid
/// or not allowed to be made. Otherwise, protocol errors are reported
/// through the `future-incoming-response`.
handle: func(request: outgoing-request, options: option<request-options>) -> result<future-incoming-response, error-code>;
}
/// The `wasi:http/proxy` world captures a widely-implementable intersection of
/// hosts that includes HTTP forward and reverse proxies. Components targeting
/// this world may concurrently stream in and out any number of incoming and
/// outgoing HTTP requests.
world proxy {
import wasi:random/random@0.2.0;
import wasi:io/error@0.2.0;
import wasi:io/poll@0.2.0;
import wasi:io/streams@0.2.0;
import wasi:cli/stdout@0.2.0;
import wasi:cli/stderr@0.2.0;
import wasi:cli/stdin@0.2.0;
import wasi:clocks/monotonic-clock@0.2.0;
import types;
import outgoing-handler;
import wasi:clocks/wall-clock@0.2.0;
export incoming-handler;
}

View File

@ -5,6 +5,9 @@ world hello {
import wasi:config/runtime@0.2.0-draft;
export wasi:http/incoming-handler@0.2.0;
export wasmcloud:messaging/handler@0.2.0;
import wasmcloud:messaging/consumer@0.2.0;
import wasi:logging/logging@0.1.0-draft;
}