diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dbc92b17b5e3..8266bb13b89f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -55,6 +55,31 @@ jobs: env: GH_TOKEN: ${{ github.token }} + # Ensure WIT dependencies are in-sync. + wit_deps: + name: WIT dependencies + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: true + + - name: ensure `crates/wasi-preview1-component-adapter/wit/deps` are in sync + working-directory: ./crates/wasi-preview1-component-adapter + run: | + curl -Lo 'wit-deps' https://github.com/bytecodealliance/wit-deps/releases/download/v0.3.2/wit-deps-x86_64-unknown-linux-musl + chmod +x ./wit-deps + rm -rf wit/deps + ./wit-deps lock + git add -N wit/deps + git diff --exit-code + + # common logic to cancel the entire run if this job fails + - run: gh run cancel ${{ github.run_id }} + if: failure() && github.event_name != 'pull_request' + env: + GH_TOKEN: ${{ github.token }} + # Lint dependency graph for security advisories, duplicate versions, and # incompatible licences cargo_deny: diff --git a/.gitignore b/.gitignore index 9cad237bc54f..9bb8cdb54ac3 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ foo publish vendor examples/build +deps.lock diff --git a/crates/wasi-preview1-component-adapter/src/lib.rs b/crates/wasi-preview1-component-adapter/src/lib.rs index d10fc48cd87d..820eda51fecc 100644 --- a/crates/wasi-preview1-component-adapter/src/lib.rs +++ b/crates/wasi-preview1-component-adapter/src/lib.rs @@ -30,7 +30,6 @@ use crate::descriptors::{Descriptor, Descriptors, StreamType, Streams}; pub mod bindings { #[cfg(feature = "command")] wit_bindgen::generate!({ - path: "../wasi/wit", world: "wasi:preview/command", std_feature, raw_strings, @@ -41,7 +40,6 @@ pub mod bindings { #[cfg(feature = "reactor")] wit_bindgen::generate!({ - path: "../wasi/wit", world: "wasi:preview/reactor", std_feature, raw_strings, diff --git a/crates/wasi-preview1-component-adapter/wit/command.wit b/crates/wasi-preview1-component-adapter/wit/command.wit deleted file mode 100644 index 29845b60e887..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/command.wit +++ /dev/null @@ -1,26 +0,0 @@ -default world command { - import wall-clock: clocks.wall-clock - import monotonic-clock: clocks.monotonic-clock - import timezone: clocks.timezone - import filesystem: filesystem.filesystem - import instance-network: sockets.instance-network - import ip-name-lookup: sockets.ip-name-lookup - import network: sockets.network - import tcp-create-socket: sockets.tcp-create-socket - import tcp: sockets.tcp - import udp-create-socket: sockets.udp-create-socket - import udp: sockets.udp - import random: random.random - import insecure-random: random.insecure - import insecure-random-seed: random.insecure-seed - import poll: poll.poll - import streams: io.streams - import environment: wasi-cli-base.environment - import preopens: wasi-cli-base.preopens - import stdin: wasi-cli-base.stdio.stdin - import stdout: wasi-cli-base.stdio.stdout - import stderr: wasi-cli-base.stdio.stderr - import exit: wasi-cli-base.exit - - export run: func() -> result -} diff --git a/crates/wasi-preview1-component-adapter/wit/deps.toml b/crates/wasi-preview1-component-adapter/wit/deps.toml new file mode 100644 index 000000000000..7f7b7d73b47e --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps.toml @@ -0,0 +1 @@ +wasi = "../../wasi/wit" diff --git a/crates/wasi-preview1-component-adapter/wit/deps/clocks/monotonic-clock.wit b/crates/wasi-preview1-component-adapter/wit/deps/clocks/monotonic-clock.wit new file mode 100644 index 000000000000..50eb4de111af --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/clocks/monotonic-clock.wit @@ -0,0 +1,34 @@ +package wasi:clocks + +/// WASI Monotonic Clock is a clock API intended to let users measure elapsed +/// time. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +/// +/// A monotonic clock is a clock which has an unspecified initial value, and +/// successive reads of the clock will produce non-decreasing values. +/// +/// It is intended for measuring elapsed time. +interface monotonic-clock { + use wasi:poll/poll.{pollable} + + /// A timestamp in nanoseconds. + type instant = u64 + + /// Read the current value of the clock. + /// + /// The clock is monotonic, therefore calling this function repeatedly will + /// produce a sequence of non-decreasing values. + now: func() -> instant + + /// Query the resolution of the clock. + resolution: func() -> instant + + /// Create a `pollable` which will resolve once the specified time has been + /// reached. + subscribe: func( + when: instant, + absolute: bool + ) -> pollable +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/clocks/timezone.wit b/crates/wasi-preview1-component-adapter/wit/deps/clocks/timezone.wit new file mode 100644 index 000000000000..2b6855668e1d --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/clocks/timezone.wit @@ -0,0 +1,63 @@ +package wasi:clocks + +interface timezone { + use wall-clock.{datetime} + + /// A timezone. + /// + /// In timezones that recognize daylight saving time, also known as daylight + /// time and summer time, the information returned from the functions varies + /// over time to reflect these adjustments. + /// + /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). + type timezone = u32 + + /// Return information needed to display the given `datetime`. This includes + /// the UTC offset, the time zone name, and a flag indicating whether + /// daylight saving time is active. + /// + /// If the timezone cannot be determined for the given `datetime`, return a + /// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight + /// saving time. + display: func(this: timezone, when: datetime) -> timezone-display + + /// The same as `display`, but only return the UTC offset. + utc-offset: func(this: timezone, when: datetime) -> s32 + + /// Dispose of the specified input-stream, after which it may no longer + /// be used. + drop-timezone: func(this: timezone) + + /// Information useful for displaying the timezone of a specific `datetime`. + /// + /// This information may vary within a single `timezone` to reflect daylight + /// saving time adjustments. + record timezone-display { + /// The number of seconds difference between UTC time and the local + /// time of the timezone. + /// + /// The returned value will always be less than 86400 which is the + /// number of seconds in a day (24*60*60). + /// + /// In implementations that do not expose an actual time zone, this + /// should return 0. + utc-offset: s32, + + /// The abbreviated name of the timezone to display to a user. The name + /// `UTC` indicates Coordinated Universal Time. Otherwise, this should + /// reference local standards for the name of the time zone. + /// + /// In implementations that do not expose an actual time zone, this + /// should be the string `UTC`. + /// + /// In time zones that do not have an applicable name, a formatted + /// representation of the UTC offset may be returned, such as `-04:00`. + name: string, + + /// Whether daylight saving time is active. + /// + /// In implementations that do not expose an actual time zone, this + /// should return false. + in-daylight-saving-time: bool, + } +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/clocks/wall-clock.wit b/crates/wasi-preview1-component-adapter/wit/deps/clocks/wall-clock.wit new file mode 100644 index 000000000000..6137724f60b1 --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/clocks/wall-clock.wit @@ -0,0 +1,43 @@ +package wasi:clocks + +/// WASI Wall Clock is a clock API intended to let users query the current +/// time. The name "wall" makes an analogy to a "clock on the wall", which +/// is not necessarily monotonic as it may be reset. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +/// +/// A wall clock is a clock which measures the date and time according to +/// some external reference. +/// +/// External references may be reset, so this clock is not necessarily +/// monotonic, making it unsuitable for measuring elapsed time. +/// +/// It is intended for reporting the current date and time for humans. +interface wall-clock { + /// A time and date in seconds plus nanoseconds. + record datetime { + seconds: u64, + nanoseconds: u32, + } + + /// Read the current value of the clock. + /// + /// This clock is not monotonic, therefore calling this function repeatedly + /// will not necessarily produce a sequence of non-decreasing values. + /// + /// The returned timestamps represent the number of seconds since + /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch], + /// also known as [Unix Time]. + /// + /// The nanoseconds field of the output is always less than 1000000000. + /// + /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16 + /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time + now: func() -> datetime + + /// Query the resolution of the clock. + /// + /// The nanoseconds field of the output is always less than 1000000000. + resolution: func() -> datetime +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/filesystem/filesystem.wit b/crates/wasi-preview1-component-adapter/wit/deps/filesystem/filesystem.wit index a5716427829a..930f37567044 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/filesystem/filesystem.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/filesystem/filesystem.wit @@ -1,3 +1,5 @@ +package wasi:filesystem + /// WASI filesystem is a filesystem API primarily intended to let users run WASI /// programs that access their files on their existing filesystems, without /// significant overhead. @@ -17,9 +19,9 @@ /// `..` and symbolic link steps, reaches a directory outside of the base /// directory, or reaches a symlink to an absolute or rooted path in the /// underlying filesystem, the function fails with `error-code::not-permitted`. -default interface filesystem { - use io.streams.{input-stream, output-stream} - use clocks.wall-clock.{datetime} +interface filesystem { + use wasi:io/streams.{input-stream, output-stream} + use wasi:clocks/wall-clock.{datetime} /// File size or length of a region within a file. type filesize = u64 @@ -309,30 +311,30 @@ default interface filesystem { /// Multiple read, write, and append streams may be active on the same open /// file and they do not interfere with each other. /// - /// Note: This allows using `read-stream`, which is similar to `read` in POSIX. + /// Note: This allows using `wasi:io/streams.read`, which is similar to `read` in POSIX. read-via-stream: func( this: descriptor, /// The offset within the file at which to start reading. offset: filesize, - ) -> input-stream + ) -> result /// Return a stream for writing to a file. /// - /// Note: This allows using `write-stream`, which is similar to `write` in + /// Note: This allows using `wasi:io/streams.write`, which is similar to `write` in /// POSIX. write-via-stream: func( this: descriptor, /// The offset within the file at which to start writing. offset: filesize, - ) -> output-stream + ) -> result /// Return a stream for appending to a file. /// - /// Note: This allows using `write-stream`, which is similar to `write` with + /// Note: This allows using `wasi:io/streams.write`, which is similar to `write` with /// `O_APPEND` in in POSIX. append-via-stream: func( this: descriptor, - ) -> output-stream + ) -> result /// Provide file advisory information on a descriptor. /// diff --git a/crates/wasi-preview1-component-adapter/wit/deps/http/incoming-handler.wit b/crates/wasi-preview1-component-adapter/wit/deps/http/incoming-handler.wit new file mode 100644 index 000000000000..d0e270465593 --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/http/incoming-handler.wit @@ -0,0 +1,24 @@ +// The `wasi:http/incoming-handler` interface is meant to be exported by +// components and called by the host in response to a new incoming HTTP +// response. +// +// NOTE: in Preview3, this interface will be merged with +// `wasi:http/outgoing-handler` into a single `wasi:http/handler` interface +// that takes a `request` parameter and returns a `response` result. +// +interface incoming-handler { + use types.{incoming-request, response-outparam} + + // The `handle` function takes an outparam instead of returning its response + // so that the component may stream its response while streaming any other + // request or response bodies. The callee MUST write a response to the + // `response-out` and then finish the response before returning. The `handle` + // function is allowed to continue execution after finishing the response's + // output stream. While this post-response execution is taken off the + // critical path, since there is no return value, there is no way to report + // its success or failure. + handle: func( + request: incoming-request, + response-out: response-outparam + ) +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/http/outgoing-handler.wit b/crates/wasi-preview1-component-adapter/wit/deps/http/outgoing-handler.wit new file mode 100644 index 000000000000..06c8e469f95b --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/http/outgoing-handler.wit @@ -0,0 +1,18 @@ +// The `wasi:http/outgoing-handler` interface is meant to be imported by +// components and implemented by the host. +// +// NOTE: in Preview3, this interface will be merged with +// `wasi:http/outgoing-handler` into a single `wasi:http/handler` interface +// that takes a `request` parameter and returns a `response` result. +// +interface outgoing-handler { + use types.{outgoing-request, request-options, future-incoming-response} + + // The parameter and result types of the `handle` function allow the caller + // to concurrently stream the bodies of the outgoing request and the incoming + // response. + handle: func( + request: outgoing-request, + options: option + ) -> future-incoming-response +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/http/types.wit b/crates/wasi-preview1-component-adapter/wit/deps/http/types.wit new file mode 100644 index 000000000000..ee4227f423a8 --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/http/types.wit @@ -0,0 +1,159 @@ +package wasi:http + +// The `wasi:http/types` interface is meant to be imported by components to +// define the HTTP resource types and operations used by the component's +// imported and exported interfaces. +interface types { + use wasi:io/streams.{input-stream, output-stream} + use wasi:poll/poll.{pollable} + + // This type corresponds to HTTP standard Methods. + variant method { + get, + head, + post, + put, + delete, + connect, + options, + trace, + patch, + other(string) + } + + // This type corresponds to HTTP standard Related Schemes. + variant scheme { + HTTP, + HTTPS, + other(string) + } + + // TODO: perhaps better align with HTTP semantics? + // This type enumerates the different kinds of errors that may occur when + // initially returning a response. + variant error { + invalid-url(string), + timeout-error(string), + protocol-error(string), + unexpected-error(string) + } + + // This following block defines the `fields` resource which corresponds to + // HTTP standard Fields. Soon, when resource types are added, the `type + // fields = u32` type alias can be replaced by a proper `resource fields` + // definition containing all the functions using the method syntactic sugar. + type fields = u32 + drop-fields: func(fields: fields) + new-fields: func(entries: list>) -> fields + fields-get: func(fields: fields, name: string) -> list + fields-set: func(fields: fields, name: string, value: list) + fields-delete: func(fields: fields, name: string) + fields-append: func(fields: fields, name: string, value: string) + fields-entries: func(fields: fields) -> list> + fields-clone: func(fields: fields) -> fields + + type headers = fields + type trailers = fields + + // The following block defines stream types which corresponds to the HTTP + // standard Contents and Trailers. With Preview3, all of these fields can be + // replaced by a stream>. In the interim, we need to + // build on separate resource types defined by `wasi:io/streams`. The + // `finish-` functions emulate the stream's result value and MUST be called + // exactly once after the final read/write from/to the stream before dropping + // the stream. + type incoming-stream = input-stream + type outgoing-stream = output-stream + finish-incoming-stream: func(s: incoming-stream) -> option + finish-outgoing-stream: func(s: outgoing-stream, trailers: option) + + // The following block defines the `incoming-request` and `outgoing-request` + // resource types that correspond to HTTP standard Requests. Soon, when + // resource types are added, the `u32` type aliases can be replaced by + // proper `resource` type definitions containing all the functions as + // methods. Later, Preview2 will allow both types to be merged together into + // a single `request` type (that uses the single `stream` type mentioned + // above). The `consume` and `write` methods may only be called once (and + // return failure thereafter). + type incoming-request = u32 + type outgoing-request = u32 + drop-incoming-request: func(request: incoming-request) + drop-outgoing-request: func(request: outgoing-request) + incoming-request-method: func(request: incoming-request) -> method + incoming-request-path: func(request: incoming-request) -> string + incoming-request-query: func(request: incoming-request) -> string + incoming-request-scheme: func(request: incoming-request) -> option + incoming-request-authority: func(request: incoming-request) -> string + incoming-request-headers: func(request: incoming-request) -> headers + incoming-request-consume: func(request: incoming-request) -> result + new-outgoing-request: func( + method: method, + path: string, + query: string, + scheme: option, + authority: string, + headers: headers + ) -> outgoing-request + outgoing-request-write: func(request: outgoing-request) -> result + + // Additional optional parameters that can be set when making a request. + record request-options { + // The following timeouts are specific to the HTTP protocol and work + // independently of the overall timeouts passed to `io.poll.poll-oneoff`. + + // The timeout for the initial connect. + connect-timeout-ms: option, + + // The timeout for receiving the first byte of the response body. + first-byte-timeout-ms: option, + + // The timeout for receiving the next chunk of bytes in the response body + // stream. + between-bytes-timeout-ms: option + } + + // The following block defines a special resource type used by the + // `wasi:http/incoming-handler` interface. When resource types are added, this + // block can be replaced by a proper `resource response-outparam { ... }` + // definition. Later, with Preview3, the need for an outparam goes away entirely + // (the `wasi:http/handler` interface used for both incoming and outgoing can + // simply return a `stream`). + type response-outparam = u32 + drop-response-outparam: func(response: response-outparam) + set-response-outparam: func(response: result) -> result + + // This type corresponds to the HTTP standard Status Code. + type status-code = u16 + + // The following block defines the `incoming-response` and `outgoing-response` + // resource types that correspond to HTTP standard Responses. Soon, when + // resource types are added, the `u32` type aliases can be replaced by proper + // `resource` type definitions containing all the functions as methods. Later, + // Preview2 will allow both types to be merged together into a single `response` + // type (that uses the single `stream` type mentioned above). The `consume` and + // `write` methods may only be called once (and return failure thereafter). + type incoming-response = u32 + type outgoing-response = u32 + drop-incoming-response: func(response: incoming-response) + drop-outgoing-response: func(response: outgoing-response) + incoming-response-status: func(response: incoming-response) -> status-code + incoming-response-headers: func(response: incoming-response) -> headers + incoming-response-consume: func(response: incoming-response) -> result + new-outgoing-response: func( + status-code: status-code, + headers: headers + ) -> outgoing-response + outgoing-response-write: func(response: outgoing-response) -> result + + // The following block defines a special resource type used by the + // `wasi:http/outgoing-handler` interface to emulate + // `future>` in advance of Preview3. Given a + // `future-incoming-response`, the client can call the non-blocking `get` + // method to get the result if it is available. If the result is not available, + // the client can call `listen` to get a `pollable` that can be passed to + // `io.poll.poll-oneoff`. + type future-incoming-response = u32 + drop-future-incoming-response: func(f: future-incoming-response) + future-incoming-response-get: func(f: future-incoming-response) -> option> + listen-to-future-incoming-response: func(f: future-incoming-response) -> pollable +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/io/streams.wit b/crates/wasi-preview1-component-adapter/wit/deps/io/streams.wit new file mode 100644 index 000000000000..008e36cf59c8 --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/io/streams.wit @@ -0,0 +1,215 @@ +package wasi:io + +/// WASI I/O is an I/O abstraction API which is currently focused on providing +/// stream types. +/// +/// In the future, the component model is expected to add built-in stream types; +/// when it does, they are expected to subsume this API. +interface streams { + use wasi:poll/poll.{pollable} + + /// An error type returned from a stream operation. Currently this + /// doesn't provide any additional information. + record stream-error {} + + /// An input bytestream. In the future, this will be replaced by handle + /// types. + /// + /// This conceptually represents a `stream`. It's temporary + /// scaffolding until component-model's async features are ready. + /// + /// `input-stream`s are *non-blocking* to the extent practical on underlying + /// platforms. I/O operations always return promptly; if fewer bytes are + /// promptly available than requested, they return the number of bytes promptly + /// available, which could even be zero. To wait for data to be available, + /// use the `subscribe-to-input-stream` function to obtain a `pollable` which + /// can be polled for using `wasi_poll`. + /// + /// And at present, it is a `u32` instead of being an actual handle, until + /// the wit-bindgen implementation of handles and resources is ready. + /// + /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). + type input-stream = u32 + + /// Read bytes from a stream. + /// + /// This function returns a list of bytes containing the data that was + /// read, along with a bool which, when true, indicates that the end of the + /// stream was reached. The returned list will contain up to `len` bytes; it + /// may return fewer than requested, but not more. + /// + /// Once a stream has reached the end, subsequent calls to read or + /// `skip` will always report end-of-stream rather than producing more + /// data. + /// + /// If `len` is 0, it represents a request to read 0 bytes, which should + /// always succeed, assuming the stream hasn't reached its end yet, and + /// return an empty list. + /// + /// The len here is a `u64`, but some callees may not be able to allocate + /// a buffer as large as that would imply. + /// FIXME: describe what happens if allocation fails. + read: func( + this: input-stream, + /// The maximum number of bytes to read + len: u64 + ) -> result, bool>, stream-error> + + /// Read bytes from a stream, with blocking. + /// + /// This is similar to `read`, except that it blocks until at least one + /// byte can be read. + blocking-read: func( + this: input-stream, + /// The maximum number of bytes to read + len: u64 + ) -> result, bool>, stream-error> + + /// Skip bytes from a stream. + /// + /// This is similar to the `read` function, but avoids copying the + /// bytes into the instance. + /// + /// Once a stream has reached the end, subsequent calls to read or + /// `skip` will always report end-of-stream rather than producing more + /// data. + /// + /// This function returns the number of bytes skipped, along with a bool + /// indicating whether the end of the stream was reached. The returned + /// value will be at most `len`; it may be less. + skip: func( + this: input-stream, + /// The maximum number of bytes to skip. + len: u64, + ) -> result, stream-error> + + /// Skip bytes from a stream, with blocking. + /// + /// This is similar to `skip`, except that it blocks until at least one + /// byte can be consumed. + blocking-skip: func( + this: input-stream, + /// The maximum number of bytes to skip. + len: u64, + ) -> result, stream-error> + + /// Create a `pollable` which will resolve once either the specified stream + /// has bytes available to read or the other end of the stream has been + /// closed. + subscribe-to-input-stream: func(this: input-stream) -> pollable + + /// Dispose of the specified `input-stream`, after which it may no longer + /// be used. + drop-input-stream: func(this: input-stream) + + /// An output bytestream. In the future, this will be replaced by handle + /// types. + /// + /// This conceptually represents a `stream`. It's temporary + /// scaffolding until component-model's async features are ready. + /// + /// `output-stream`s are *non-blocking* to the extent practical on + /// underlying platforms. Except where specified otherwise, I/O operations also + /// always return promptly, after the number of bytes that can be written + /// promptly, which could even be zero. To wait for the stream to be ready to + /// accept data, the `subscribe-to-output-stream` function to obtain a + /// `pollable` which can be polled for using `wasi_poll`. + /// + /// And at present, it is a `u32` instead of being an actual handle, until + /// the wit-bindgen implementation of handles and resources is ready. + /// + /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). + type output-stream = u32 + + /// Write bytes to a stream. + /// + /// This function returns a `u64` indicating the number of bytes from + /// `buf` that were written; it may be less than the full list. + write: func( + this: output-stream, + /// Data to write + buf: list + ) -> result + + /// Write bytes to a stream, with blocking. + /// + /// This is similar to `write`, except that it blocks until at least one + /// byte can be written. + blocking-write: func( + this: output-stream, + /// Data to write + buf: list + ) -> result + + /// Write multiple zero bytes to a stream. + /// + /// This function returns a `u64` indicating the number of zero bytes + /// that were written; it may be less than `len`. + write-zeroes: func( + this: output-stream, + /// The number of zero bytes to write + len: u64 + ) -> result + + /// Write multiple zero bytes to a stream, with blocking. + /// + /// This is similar to `write-zeroes`, except that it blocks until at least + /// one byte can be written. + blocking-write-zeroes: func( + this: output-stream, + /// The number of zero bytes to write + len: u64 + ) -> result + + /// Read from one stream and write to another. + /// + /// This function returns the number of bytes transferred; it may be less + /// than `len`. + /// + /// Unlike other I/O functions, this function blocks until all the data + /// read from the input stream has been written to the output stream. + splice: func( + this: output-stream, + /// The stream to read from + src: input-stream, + /// The number of bytes to splice + len: u64, + ) -> result, stream-error> + + /// Read from one stream and write to another, with blocking. + /// + /// This is similar to `splice`, except that it blocks until at least + /// one byte can be read. + blocking-splice: func( + this: output-stream, + /// The stream to read from + src: input-stream, + /// The number of bytes to splice + len: u64, + ) -> result, stream-error> + + /// Forward the entire contents of an input stream to an output stream. + /// + /// This function repeatedly reads from the input stream and writes + /// the data to the output stream, until the end of the input stream + /// is reached, or an error is encountered. + /// + /// Unlike other I/O functions, this function blocks until the end + /// of the input stream is seen and all the data has been written to + /// the output stream. + /// + /// This function returns the number of bytes transferred. + forward: func( + this: output-stream, + /// The stream to read from + src: input-stream + ) -> result + + /// Create a `pollable` which will resolve once either the specified stream + /// is ready to accept bytes or the other end of the stream has been closed. + subscribe-to-output-stream: func(this: output-stream) -> pollable + + /// Dispose of the specified `output-stream`, after which it may no longer + /// be used. + drop-output-stream: func(this: output-stream) +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/logging/handler.wit b/crates/wasi-preview1-component-adapter/wit/deps/logging/handler.wit new file mode 100644 index 000000000000..e6b077be8a60 --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/logging/handler.wit @@ -0,0 +1,34 @@ +package wasi:logging + +/// WASI Logging is a logging API intended to let users emit log messages with +/// simple priority levels and context values. +interface handler { + /// A log level, describing a kind of message. + enum level { + /// Describes messages about the values of variables and the flow of + /// control within a program. + trace, + + /// Describes messages likely to be of interest to someone debugging a + /// program. + debug, + + /// Describes messages likely to be of interest to someone monitoring a + /// program. + info, + + /// Describes messages indicating hazardous situations. + warn, + + /// Describes messages indicating serious errors. + error, + } + + /// Emit a log message. + /// + /// A log message has a `level` describing what kind of message is being + /// sent, a context, which is an uninterpreted string meant to help + /// consumers group similar messages, and a string containing the message + /// text. + log: func(level: level, context: string, message: string) +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/poll/poll.wit b/crates/wasi-preview1-component-adapter/wit/deps/poll/poll.wit new file mode 100644 index 000000000000..cf5d8779c17e --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/poll/poll.wit @@ -0,0 +1,41 @@ +package wasi:poll + +/// A poll API intended to let users wait for I/O events on multiple handles +/// at once. +interface poll { + /// A "pollable" handle. + /// + /// This is conceptually represents a `stream<_, _>`, or in other words, + /// a stream that one can wait on, repeatedly, but which does not itself + /// produce any data. It's temporary scaffolding until component-model's + /// async features are ready. + /// + /// And at present, it is a `u32` instead of being an actual handle, until + /// the wit-bindgen implementation of handles and resources is ready. + /// + /// `pollable` lifetimes are not automatically managed. Users must ensure + /// that they do not outlive the resource they reference. + /// + /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). + type pollable = u32 + + /// Dispose of the specified `pollable`, after which it may no longer + /// be used. + drop-pollable: func(this: pollable) + + /// Poll for completion on a set of pollables. + /// + /// The "oneoff" in the name refers to the fact that this function must do a + /// linear scan through the entire list of subscriptions, which may be + /// inefficient if the number is large and the same subscriptions are used + /// many times. In the future, this is expected to be obsoleted by the + /// component model async proposal, which will include a scalable waiting + /// facility. + /// + /// Note that the return type would ideally be `list`, but that would + /// be more difficult to polyfill given the current state of `wit-bindgen`. + /// See + /// for details. For now, we use zero to mean "not ready" and non-zero to + /// mean "ready". + poll-oneoff: func(in: list) -> list +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/preview/command-extended.wit b/crates/wasi-preview1-component-adapter/wit/deps/preview/command-extended.wit index 92e3d7d81022..2beb119da319 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/preview/command-extended.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/preview/command-extended.wit @@ -1,29 +1,34 @@ -default world command-extended { - import wall-clock: clocks.wall-clock - import monotonic-clock: clocks.monotonic-clock - import timezone: clocks.timezone - import filesystem: filesystem.filesystem - import instance-network: sockets.instance-network - import ip-name-lookup: sockets.ip-name-lookup - import network: sockets.network - import tcp-create-socket: sockets.tcp-create-socket - import tcp: sockets.tcp - import udp-create-socket: sockets.udp-create-socket - import udp: sockets.udp - import random: random.random - import insecure-random: random.insecure - import insecure-random-seed: random.insecure-seed - import poll: poll.poll - import streams: io.streams - import environment: wasi-cli-base.environment - import preopens: wasi-cli-base.preopens - import exit: wasi-cli-base.exit +package wasi:preview + +world command-extended { + import wasi:clocks/wall-clock + import wasi:clocks/monotonic-clock + import wasi:clocks/timezone + import wasi:filesystem/filesystem + import wasi:sockets/instance-network + import wasi:sockets/ip-name-lookup + import wasi:sockets/network + import wasi:sockets/tcp-create-socket + import wasi:sockets/tcp + import wasi:sockets/udp-create-socket + import wasi:sockets/udp + import wasi:random/random + import wasi:random/insecure + import wasi:random/insecure-seed + import wasi:poll/poll + import wasi:io/streams + import wasi:cli-base/environment + import wasi:cli-base/preopens + import wasi:cli-base/exit + import wasi:cli-base/stdin + import wasi:cli-base/stdout + import wasi:cli-base/stderr // We should replace all others with `include self.command` // as soon as the unioning of worlds is available: // https://github.com/WebAssembly/component-model/issues/169 - import console: logging.handler - import default-outgoing-HTTP: http.outgoing-handler + import wasi:logging/handler + import wasi:http/outgoing-handler export run: func( args: list, diff --git a/crates/wasi-preview1-component-adapter/wit/deps/preview/command.wit b/crates/wasi-preview1-component-adapter/wit/deps/preview/command.wit index 780e2c4667ff..62608a05ccf9 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/preview/command.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/preview/command.wit @@ -1,23 +1,26 @@ -default world command { - import wall-clock: clocks.wall-clock - import monotonic-clock: clocks.monotonic-clock - import timezone: clocks.timezone - import filesystem: filesystem.filesystem - import instance-network: sockets.instance-network - import ip-name-lookup: sockets.ip-name-lookup - import network: sockets.network - import tcp-create-socket: sockets.tcp-create-socket - import tcp: sockets.tcp - import udp-create-socket: sockets.udp-create-socket - import udp: sockets.udp - import random: random.random - import insecure-random: random.insecure - import insecure-random-seed: random.insecure-seed - import poll: poll.poll - import streams: io.streams - import environment: wasi-cli-base.environment - import preopens: wasi-cli-base.preopens - import exit: wasi-cli-base.exit +world command { + import wasi:clocks/wall-clock + import wasi:clocks/monotonic-clock + import wasi:clocks/timezone + import wasi:filesystem/filesystem + import wasi:sockets/instance-network + import wasi:sockets/ip-name-lookup + import wasi:sockets/network + import wasi:sockets/tcp-create-socket + import wasi:sockets/tcp + import wasi:sockets/udp-create-socket + import wasi:sockets/udp + import wasi:random/random + import wasi:random/insecure + import wasi:random/insecure-seed + import wasi:poll/poll + import wasi:io/streams + import wasi:cli-base/environment + import wasi:cli-base/preopens + import wasi:cli-base/exit + import wasi:cli-base/stdin + import wasi:cli-base/stdout + import wasi:cli-base/stderr export run: func() -> result } diff --git a/crates/wasi-preview1-component-adapter/wit/deps/preview/proxy.wit b/crates/wasi-preview1-component-adapter/wit/deps/preview/proxy.wit index 03877e958e92..a616daa1c243 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/preview/proxy.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/preview/proxy.wit @@ -1,8 +1,9 @@ -default world proxy { - import random: random.random - import insecure-random: random.insecure - import insecure-random-seed: random.insecure-seed - import console: logging.handler - import default-outgoing-HTTP: http.outgoing-handler - export HTTP: http.incoming-handler +world proxy { + import wasi:random/random + import wasi:random/insecure + import wasi:random/insecure-seed + import wasi:logging/handler + import wasi:http/outgoing-handler + + export wasi:http/incoming-handler } diff --git a/crates/wasi-preview1-component-adapter/wit/deps/preview/reactor.wit b/crates/wasi-preview1-component-adapter/wit/deps/preview/reactor.wit new file mode 100644 index 000000000000..4a262c551d3f --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/preview/reactor.wit @@ -0,0 +1,24 @@ +world reactor { + import wasi:clocks/wall-clock + import wasi:clocks/monotonic-clock + import wasi:clocks/timezone + import wasi:filesystem/filesystem + import wasi:sockets/instance-network + import wasi:sockets/ip-name-lookup + import wasi:sockets/network + import wasi:sockets/tcp-create-socket + import wasi:sockets/tcp + import wasi:sockets/udp-create-socket + import wasi:sockets/udp + import wasi:random/random + import wasi:poll/poll + import wasi:io/streams + import wasi:logging/handler + import wasi:http/outgoing-handler + import wasi:cli-base/environment + import wasi:cli-base/preopens + import wasi:cli-base/exit + import wasi:cli-base/stdin + import wasi:cli-base/stdout + import wasi:cli-base/stderr +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/random/insecure-seed.wit b/crates/wasi-preview1-component-adapter/wit/deps/random/insecure-seed.wit index 93a2f17d4090..ff2ff65d0754 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/random/insecure-seed.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/random/insecure-seed.wit @@ -2,7 +2,7 @@ /// /// It is intended to be portable at least between Unix-family platforms and /// Windows. -default interface insecure-seed { +interface insecure-seed { /// Return a 128-bit value that may contain a pseudo-random value. /// /// The returned value is not required to be computed from a CSPRNG, and may diff --git a/crates/wasi-preview1-component-adapter/wit/deps/random/insecure.wit b/crates/wasi-preview1-component-adapter/wit/deps/random/insecure.wit index 1ef020a0998c..ff0826822d5f 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/random/insecure.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/random/insecure.wit @@ -2,7 +2,7 @@ /// /// It is intended to be portable at least between Unix-family platforms and /// Windows. -default interface insecure { +interface insecure { /// Return `len` insecure pseudo-random bytes. /// /// This function is not cryptographically secure. Do not use it for diff --git a/crates/wasi-preview1-component-adapter/wit/deps/random/random.wit b/crates/wasi-preview1-component-adapter/wit/deps/random/random.wit index 8f758578842f..f2bd6358c139 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/random/random.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/random/random.wit @@ -1,8 +1,10 @@ +package wasi:random + /// WASI Random is a random data API. /// /// It is intended to be portable at least between Unix-family platforms and /// Windows. -default interface random { +interface random { /// Return `len` cryptographically-secure pseudo-random bytes. /// /// This function must produce data from an adequately seeded diff --git a/crates/wasi-preview1-component-adapter/wit/deps/sockets/instance-network.wit b/crates/wasi-preview1-component-adapter/wit/deps/sockets/instance-network.wit new file mode 100644 index 000000000000..d911a29cc8dd --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/sockets/instance-network.wit @@ -0,0 +1,9 @@ + +/// This interface provides a value-export of the default network handle.. +interface instance-network { + use network.{network} + + /// Get a handle to the default network. + instance-network: func() -> network + +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/sockets/ip-name-lookup.wit b/crates/wasi-preview1-component-adapter/wit/deps/sockets/ip-name-lookup.wit index c4cc7268464c..6c64b4617b98 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/sockets/ip-name-lookup.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/sockets/ip-name-lookup.wit @@ -1,13 +1,13 @@ -default interface ip-name-lookup { - use poll.poll.{pollable} - use pkg.network.{network, error-code, ip-address, ip-address-family} +interface ip-name-lookup { + use wasi:poll/poll.{pollable} + use network.{network, error-code, ip-address, ip-address-family} /// Resolve an internet host name to a list of IP addresses. - /// + /// /// See the wasi-socket proposal README.md for a comparison with getaddrinfo. - /// + /// /// # Parameters /// - `name`: The name to look up. IP addresses are not allowed. Unicode domain names are automatically converted /// to ASCII using IDNA encoding. @@ -17,18 +17,18 @@ default interface ip-name-lookup { /// systems without an active IPv6 interface. Notes: /// - Even when no public IPv6 interfaces are present or active, names like "localhost" can still resolve to an IPv6 address. /// - Whatever is "available" or "unavailable" is volatile and can change everytime a network cable is unplugged. - /// + /// /// This function never blocks. It either immediately fails or immediately returns successfully with a `resolve-address-stream` /// that can be used to (asynchronously) fetch the results. - /// + /// /// At the moment, the stream never completes successfully with 0 items. Ie. the first call /// to `resolve-next-address` never returns `ok(none)`. This may change in the future. - /// + /// /// # Typical errors /// - `invalid-name`: `name` is a syntactically invalid domain name. /// - `invalid-name`: `name` is an IP address. /// - `address-family-not-supported`: The specified `address-family` is not supported. (EAI_FAMILY) - /// + /// /// # References: /// - /// - @@ -41,14 +41,14 @@ default interface ip-name-lookup { type resolve-address-stream = u32 /// Returns the next address from the resolver. - /// + /// /// This function should be called multiple times. On each call, it will /// return the next address in connection order preference. If all /// addresses have been exhausted, this function returns `none`. /// After which, you should release the stream with `drop-resolve-address-stream`. - /// + /// /// This function never returns IPv4-mapped IPv6 addresses. - /// + /// /// # Typical errors /// - `name-unresolvable`: Name does not exist or has no suitable associated IP addresses. (EAI_NONAME, EAI_NODATA, EAI_ADDRFAMILY) /// - `temporary-resolver-failure`: A temporary failure in name resolution occurred. (EAI_AGAIN) @@ -57,12 +57,12 @@ default interface ip-name-lookup { resolve-next-address: func(this: resolve-address-stream) -> result, error-code> /// Dispose of the specified `resolve-address-stream`, after which it may no longer be used. - /// + /// /// Note: this function is scheduled to be removed when Resources are natively supported in Wit. drop-resolve-address-stream: func(this: resolve-address-stream) /// Create a `pollable` which will resolve once the stream is ready for I/O. - /// + /// /// Note: this function is here for WASI Preview2 only. /// It's planned to be removed when `future` is natively supported in Preview3. subscribe: func(this: resolve-address-stream) -> pollable diff --git a/crates/wasi-preview1-component-adapter/wit/deps/sockets/network.wit b/crates/wasi-preview1-component-adapter/wit/deps/sockets/network.wit index 9176e6ba6594..c370214ce1f9 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/sockets/network.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/sockets/network.wit @@ -1,14 +1,15 @@ +package wasi:sockets -default interface network { +interface network { /// An opaque resource that represents access to (a subset of) the network. /// This enables context-based security for networking. /// There is no need for this to map 1:1 to a physical network interface. - /// + /// /// FYI, In the future this will be replaced by handle types. type network = u32 /// Dispose of the specified `network`, after which it may no longer be used. - /// + /// /// Note: this function is scheduled to be removed when Resources are natively supported in Wit. drop-network: func(this: network) @@ -152,7 +153,7 @@ default interface network { enum ip-address-family { /// Similar to `AF_INET` in POSIX. - ipv4, + ipv4, /// Similar to `AF_INET6` in POSIX. ipv6, @@ -183,4 +184,4 @@ default interface network { ipv6(ipv6-socket-address), } -} \ No newline at end of file +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/sockets/tcp-create-socket.wit b/crates/wasi-preview1-component-adapter/wit/deps/sockets/tcp-create-socket.wit index 6e948fae0a6c..f467d2856906 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/sockets/tcp-create-socket.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/sockets/tcp-create-socket.wit @@ -1,23 +1,23 @@ -default interface tcp-create-socket { - use pkg.network.{network, error-code, ip-address-family} - use pkg.tcp.{tcp-socket} +interface tcp-create-socket { + use network.{network, error-code, ip-address-family} + use tcp.{tcp-socket} /// Create a new TCP socket. - /// + /// /// Similar to `socket(AF_INET or AF_INET6, SOCK_STREAM, IPPROTO_TCP)` in POSIX. - /// + /// /// This function does not require a network capability handle. This is considered to be safe because /// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind`/`listen`/`connect` /// is called, the socket is effectively an in-memory configuration object, unable to communicate with the outside world. - /// + /// /// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations. - /// + /// /// # Typical errors /// - `not-supported`: The host does not support TCP sockets. (EOPNOTSUPP) /// - `address-family-not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT) /// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE) - /// + /// /// # References /// - /// - diff --git a/crates/wasi-preview1-component-adapter/wit/deps/sockets/tcp.wit b/crates/wasi-preview1-component-adapter/wit/deps/sockets/tcp.wit index b87153243c20..7ed46a690491 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/sockets/tcp.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/sockets/tcp.wit @@ -1,12 +1,12 @@ -default interface tcp { - use io.streams.{input-stream, output-stream} - use poll.poll.{pollable} - use pkg.network.{network, error-code, ip-socket-address, ip-address-family} +interface tcp { + use wasi:io/streams.{input-stream, output-stream} + use wasi:poll/poll.{pollable} + use network.{network, error-code, ip-socket-address, ip-address-family} /// A TCP socket handle. type tcp-socket = u32 - + enum shutdown-type { /// Similar to `SHUT_RD` in POSIX. @@ -25,24 +25,24 @@ default interface tcp { /// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which /// network interface(s) to bind to. /// If the TCP/UDP port is zero, the socket will be bound to a random free port. - /// + /// /// When a socket is not explicitly bound, the first invocation to a listen or connect operation will /// implicitly bind the socket. - /// + /// /// Unlike in POSIX, this function is async. This enables interactive WASI hosts to inject permission prompts. - /// + /// /// # Typical `start` errors /// - `address-family-mismatch`: The `local-address` has the wrong address family. (EINVAL) /// - `already-bound`: The socket is already bound. (EINVAL) /// - `concurrency-conflict`: Another `bind`, `connect` or `listen` operation is already in progress. (EALREADY) - /// + /// /// # Typical `finish` errors /// - `ephemeral-ports-exhausted`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows) /// - `address-in-use`: Address is already in use. (EADDRINUSE) /// - `address-not-bindable`: `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL) /// - `not-in-progress`: A `bind` operation is not in progress. /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) - /// + /// /// # References /// - /// - @@ -52,11 +52,11 @@ default interface tcp { finish-bind: func(this: tcp-socket) -> result<_, error-code> /// Connect to a remote endpoint. - /// + /// /// On success: /// - the socket is transitioned into the Connection state /// - a pair of streams is returned that can be used to read & write to the connection - /// + /// /// # Typical `start` errors /// - `address-family-mismatch`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) /// - `invalid-remote-address`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EADDRNOTAVAIL on Windows) @@ -65,7 +65,7 @@ default interface tcp { /// - `already-connected`: The socket is already in the Connection state. (EISCONN) /// - `already-listening`: The socket is already in the Listener state. (EOPNOTSUPP, EINVAL on Windows) /// - `concurrency-conflict`: Another `bind`, `connect` or `listen` operation is already in progress. (EALREADY) - /// + /// /// # Typical `finish` errors /// - `timeout`: Connection timed out. (ETIMEDOUT) /// - `connection-refused`: The connection was forcefully rejected. (ECONNREFUSED) @@ -74,7 +74,7 @@ default interface tcp { /// - `ephemeral-ports-exhausted`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD) /// - `not-in-progress`: A `connect` operation is not in progress. /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) - /// + /// /// # References /// - /// - @@ -84,11 +84,11 @@ default interface tcp { finish-connect: func(this: tcp-socket) -> result, error-code> /// Start listening for new connections. - /// + /// /// Transitions the socket into the Listener state. - /// + /// /// Unlike in POSIX, this function is async. This enables interactive WASI hosts to inject permission prompts. - /// + /// /// # Typical `start` errors /// - `already-attached`: The socket is already attached to a different network. The `network` passed to `listen` must be identical to the one passed to `bind`. /// - `already-connected`: The socket is already in the Connection state. (EISCONN, EINVAL on BSD) @@ -109,18 +109,18 @@ default interface tcp { finish-listen: func(this: tcp-socket) -> result<_, error-code> /// Accept a new client socket. - /// + /// /// The returned socket is bound and in the Connection state. - /// + /// /// On success, this function returns the newly accepted client socket along with /// a pair of streams that can be used to read & write to the connection. - /// + /// /// # Typical errors /// - `not-listening`: Socket is not in the Listener state. (EINVAL) /// - `would-block`: No pending connections at the moment. (EWOULDBLOCK, EAGAIN) - /// + /// /// Host implementations must skip over transient errors returned by the native accept syscall. - /// + /// /// # References /// - /// - @@ -129,10 +129,10 @@ default interface tcp { accept: func(this: tcp-socket) -> result, error-code> /// Get the bound local address. - /// + /// /// # Typical errors /// - `not-bound`: The socket is not bound to any local address. - /// + /// /// # References /// - /// - @@ -141,10 +141,10 @@ default interface tcp { local-address: func(this: tcp-socket) -> result /// Get the bound remote address. - /// + /// /// # Typical errors /// - `not-connected`: The socket is not connected to a remote address. (ENOTCONN) - /// + /// /// # References /// - /// - @@ -153,14 +153,14 @@ default interface tcp { remote-address: func(this: tcp-socket) -> result /// Whether this is a IPv4 or IPv6 socket. - /// + /// /// Equivalent to the SO_DOMAIN socket option. address-family: func(this: tcp-socket) -> ip-address-family - + /// Whether IPv4 compatibility (dual-stack) mode is disabled or not. - /// + /// /// Equivalent to the IPV6_V6ONLY socket option. - /// + /// /// # Typical errors /// - `ipv6-only-operation`: (get/set) `this` socket is an IPv4 socket. /// - `already-bound`: (set) The socket is already bound. @@ -170,28 +170,28 @@ default interface tcp { set-ipv6-only: func(this: tcp-socket, value: bool) -> result<_, error-code> /// Hints the desired listen queue size. Implementations are free to ignore this. - /// + /// /// # Typical errors /// - `already-connected`: (set) The socket is already in the Connection state. /// - `concurrency-conflict`: (set) A `bind`, `connect` or `listen` operation is already in progress. (EALREADY) set-listen-backlog-size: func(this: tcp-socket, value: u64) -> result<_, error-code> /// Equivalent to the SO_KEEPALIVE socket option. - /// + /// /// # Typical errors /// - `concurrency-conflict`: (set) A `bind`, `connect` or `listen` operation is already in progress. (EALREADY) keep-alive: func(this: tcp-socket) -> result set-keep-alive: func(this: tcp-socket, value: bool) -> result<_, error-code> /// Equivalent to the TCP_NODELAY socket option. - /// + /// /// # Typical errors /// - `concurrency-conflict`: (set) A `bind`, `connect` or `listen` operation is already in progress. (EALREADY) no-delay: func(this: tcp-socket) -> result set-no-delay: func(this: tcp-socket, value: bool) -> result<_, error-code> - + /// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options. - /// + /// /// # Typical errors /// - `already-connected`: (set) The socket is already in the Connection state. /// - `already-listening`: (set) The socket is already in the Listener state. @@ -200,16 +200,16 @@ default interface tcp { set-unicast-hop-limit: func(this: tcp-socket, value: u8) -> result<_, error-code> /// The kernel buffer space reserved for sends/receives on this socket. - /// + /// /// Note #1: an implementation may choose to cap or round the buffer size when setting the value. /// In other words, after setting a value, reading the same setting back may return a different value. - /// + /// /// Note #2: there is not necessarily a direct relationship between the kernel buffer size and the bytes of /// actual data to be sent/received by the application, because the kernel might also use the buffer space /// for internal metadata structures. - /// + /// /// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options. - /// + /// /// # Typical errors /// - `already-connected`: (set) The socket is already in the Connection state. /// - `already-listening`: (set) The socket is already in the Listener state. @@ -220,25 +220,25 @@ default interface tcp { set-send-buffer-size: func(this: tcp-socket, value: u64) -> result<_, error-code> /// Create a `pollable` which will resolve once the socket is ready for I/O. - /// + /// /// Note: this function is here for WASI Preview2 only. /// It's planned to be removed when `future` is natively supported in Preview3. subscribe: func(this: tcp-socket) -> pollable /// Initiate a graceful shutdown. - /// + /// /// - receive: the socket is not expecting to receive any more data from the peer. All subsequent read /// operations on the `input-stream` associated with this socket will return an End Of Stream indication. /// Any data still in the receive queue at time of calling `shutdown` will be discarded. /// - send: the socket is not expecting to send any more data to the peer. All subsequent write /// operations on the `output-stream` associated with this socket will return an error. /// - both: same effect as receive & send combined. - /// + /// /// The shutdown function does not close (drop) the socket. - /// + /// /// # Typical errors /// - `not-connected`: The socket is not in the Connection state. (ENOTCONN) - /// + /// /// # References /// - /// - @@ -247,9 +247,9 @@ default interface tcp { shutdown: func(this: tcp-socket, shutdown-type: shutdown-type) -> result<_, error-code> /// Dispose of the specified `tcp-socket`, after which it may no longer be used. - /// + /// /// Similar to the POSIX `close` function. - /// + /// /// Note: this function is scheduled to be removed when Resources are natively supported in Wit. drop-tcp-socket: func(this: tcp-socket) } diff --git a/crates/wasi-preview1-component-adapter/wit/deps/sockets/udp-create-socket.wit b/crates/wasi-preview1-component-adapter/wit/deps/sockets/udp-create-socket.wit index 2c987be08df5..1cfbd7f0bdd8 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/sockets/udp-create-socket.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/sockets/udp-create-socket.wit @@ -1,23 +1,23 @@ -default interface udp-create-socket { - use pkg.network.{network, error-code, ip-address-family} - use pkg.udp.{udp-socket} +interface udp-create-socket { + use network.{network, error-code, ip-address-family} + use udp.{udp-socket} /// Create a new UDP socket. - /// + /// /// Similar to `socket(AF_INET or AF_INET6, SOCK_DGRAM, IPPROTO_UDP)` in POSIX. - /// + /// /// This function does not require a network capability handle. This is considered to be safe because /// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind`/`connect` is called, /// the socket is effectively an in-memory configuration object, unable to communicate with the outside world. - /// + /// /// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations. - /// + /// /// # Typical errors /// - `not-supported`: The host does not support UDP sockets. (EOPNOTSUPP) /// - `address-family-not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT) /// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE) - /// + /// /// # References: /// - /// - diff --git a/crates/wasi-preview1-component-adapter/wit/deps/sockets/udp.wit b/crates/wasi-preview1-component-adapter/wit/deps/sockets/udp.wit index 271a2cb9f00f..9dd4573bd17c 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/sockets/udp.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/sockets/udp.wit @@ -1,7 +1,7 @@ -default interface udp { - use poll.poll.{pollable} - use pkg.network.{network, error-code, ip-socket-address, ip-address-family} +interface udp { + use wasi:poll/poll.{pollable} + use network.{network, error-code, ip-socket-address, ip-address-family} /// A UDP socket handle. @@ -27,23 +27,23 @@ default interface udp { /// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which /// network interface(s) to bind to. /// If the TCP/UDP port is zero, the socket will be bound to a random free port. - /// + /// /// When a socket is not explicitly bound, the first invocation to connect will implicitly bind the socket. - /// + /// /// Unlike in POSIX, this function is async. This enables interactive WASI hosts to inject permission prompts. - /// + /// /// # Typical `start` errors /// - `address-family-mismatch`: The `local-address` has the wrong address family. (EINVAL) /// - `already-bound`: The socket is already bound. (EINVAL) /// - `concurrency-conflict`: Another `bind` or `connect` operation is already in progress. (EALREADY) - /// + /// /// # Typical `finish` errors /// - `ephemeral-ports-exhausted`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows) /// - `address-in-use`: Address is already in use. (EADDRINUSE) /// - `address-not-bindable`: `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL) /// - `not-in-progress`: A `bind` operation is not in progress. /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) - /// + /// /// # References /// - /// - @@ -53,29 +53,29 @@ default interface udp { finish-bind: func(this: udp-socket) -> result<_, error-code> /// Set the destination address. - /// + /// /// The local-address is updated based on the best network path to `remote-address`. - /// + /// /// When a destination address is set: /// - all receive operations will only return datagrams sent from the provided `remote-address`. /// - the `send` function can only be used to send to this destination. - /// + /// /// Note that this function does not generate any network traffic and the peer is not aware of this "connection". - /// + /// /// Unlike in POSIX, this function is async. This enables interactive WASI hosts to inject permission prompts. - /// + /// /// # Typical `start` errors /// - `address-family-mismatch`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) /// - `invalid-remote-address`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL) /// - `invalid-remote-address`: The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL) /// - `already-attached`: The socket is already bound to a different network. The `network` passed to `connect` must be identical to the one passed to `bind`. /// - `concurrency-conflict`: Another `bind` or `connect` operation is already in progress. (EALREADY) - /// + /// /// # Typical `finish` errors /// - `ephemeral-ports-exhausted`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD) /// - `not-in-progress`: A `connect` operation is not in progress. /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) - /// + /// /// # References /// - /// - @@ -85,16 +85,16 @@ default interface udp { finish-connect: func(this: udp-socket) -> result<_, error-code> /// Receive a message. - /// + /// /// Returns: /// - The sender address of the datagram /// - The number of bytes read. - /// + /// /// # Typical errors /// - `not-bound`: The socket is not bound to any local address. (EINVAL) /// - `remote-unreachable`: The remote address is not reachable. (ECONNREFUSED, ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN) /// - `would-block`: There is no pending data available to be read at the moment. (EWOULDBLOCK, EAGAIN) - /// + /// /// # References /// - /// - @@ -106,10 +106,10 @@ default interface udp { receive: func(this: udp-socket) -> result /// Send a message to a specific destination address. - /// + /// /// The remote address option is required. To send a message to the "connected" peer, /// call `remote-address` to get their address. - /// + /// /// # Typical errors /// - `address-family-mismatch`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) /// - `invalid-remote-address`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL) @@ -119,7 +119,7 @@ default interface udp { /// - `remote-unreachable`: The remote address is not reachable. (ECONNREFUSED, ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN) /// - `datagram-too-large`: The datagram is too large. (EMSGSIZE) /// - `would-block`: The send buffer is currently full. (EWOULDBLOCK, EAGAIN) - /// + /// /// # References /// - /// - @@ -131,10 +131,10 @@ default interface udp { send: func(this: udp-socket, datagram: datagram) -> result<_, error-code> /// Get the current bound address. - /// + /// /// # Typical errors /// - `not-bound`: The socket is not bound to any local address. - /// + /// /// # References /// - /// - @@ -143,10 +143,10 @@ default interface udp { local-address: func(this: udp-socket) -> result /// Get the address set with `connect`. - /// + /// /// # Typical errors /// - `not-connected`: The socket is not connected to a remote address. (ENOTCONN) - /// + /// /// # References /// - /// - @@ -155,14 +155,14 @@ default interface udp { remote-address: func(this: udp-socket) -> result /// Whether this is a IPv4 or IPv6 socket. - /// + /// /// Equivalent to the SO_DOMAIN socket option. address-family: func(this: udp-socket) -> ip-address-family /// Whether IPv4 compatibility (dual-stack) mode is disabled or not. - /// + /// /// Equivalent to the IPV6_V6ONLY socket option. - /// + /// /// # Typical errors /// - `ipv6-only-operation`: (get/set) `this` socket is an IPv4 socket. /// - `already-bound`: (set) The socket is already bound. @@ -172,25 +172,25 @@ default interface udp { set-ipv6-only: func(this: udp-socket, value: bool) -> result<_, error-code> /// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options. - /// + /// /// # Typical errors /// - `concurrency-conflict`: (set) Another `bind` or `connect` operation is already in progress. (EALREADY) unicast-hop-limit: func(this: udp-socket) -> result set-unicast-hop-limit: func(this: udp-socket, value: u8) -> result<_, error-code> /// The kernel buffer space reserved for sends/receives on this socket. - /// + /// /// Note #1: an implementation may choose to cap or round the buffer size when setting the value. /// In other words, after setting a value, reading the same setting back may return a different value. - /// + /// /// Note #2: there is not necessarily a direct relationship between the kernel buffer size and the bytes of /// actual data to be sent/received by the application, because the kernel might also use the buffer space /// for internal metadata structures. - /// + /// /// Fails when this socket is in the Listening state. - /// + /// /// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options. - /// + /// /// # Typical errors /// - `concurrency-conflict`: (set) Another `bind` or `connect` operation is already in progress. (EALREADY) receive-buffer-size: func(this: udp-socket) -> result @@ -199,13 +199,13 @@ default interface udp { set-send-buffer-size: func(this: udp-socket, value: u64) -> result<_, error-code> /// Create a `pollable` which will resolve once the socket is ready for I/O. - /// + /// /// Note: this function is here for WASI Preview2 only. /// It's planned to be removed when `future` is natively supported in Preview3. subscribe: func(this: udp-socket) -> pollable /// Dispose of the specified `udp-socket`, after which it may no longer be used. - /// + /// /// Note: this function is scheduled to be removed when Resources are natively supported in Wit. drop-udp-socket: func(this: udp-socket) } diff --git a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/environment.wit b/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/environment.wit new file mode 100644 index 000000000000..4c97c85d1ab5 --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/environment.wit @@ -0,0 +1,16 @@ +package wasi:cli-base + +interface environment { + /// Get the POSIX-style environment variables. + /// + /// Each environment variable is provided as a pair of string variable names + /// and string value. + /// + /// Morally, these are a value import, but until value imports are available + /// in the component model, this import function should return the same + /// values each time it is called. + get-environment: func() -> list> + + /// Get the POSIX-style arguments to the program. + get-arguments: func() -> list +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/exit.wit b/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/exit.wit new file mode 100644 index 000000000000..66835aa7022d --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/exit.wit @@ -0,0 +1,4 @@ +interface exit { + /// Exit the curerent instance and any linked instances. + exit: func(status: result) +} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/preopens.wit b/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/preopens.wit index 5595f8d392a2..f268f6b0b2e6 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/preopens.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/preopens.wit @@ -1,6 +1,6 @@ -default interface preopens { - use filesystem.filesystem.{descriptor} - use io.streams.{input-stream, output-stream} +interface preopens { + use wasi:filesystem/filesystem.{descriptor} + use wasi:io/streams.{input-stream, output-stream} /// Return the set of of preopened directories, and their path. get-directories: func() -> list> diff --git a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/stdio.wit b/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/stdio.wit index 1f87e5485abb..6c9d4a41a6f9 100644 --- a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/stdio.wit +++ b/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/stdio.wit @@ -1,17 +1,17 @@ interface stdin { - use io.streams.{input-stream} + use wasi:io/streams.{input-stream} get-stdin: func() -> input-stream } interface stdout { - use io.streams.{output-stream} + use wasi:io/streams.{output-stream} get-stdout: func() -> output-stream } interface stderr { - use io.streams.{output-stream} + use wasi:io/streams.{output-stream} get-stderr: func() -> output-stream } diff --git a/crates/wasi-preview1-component-adapter/wit/deps/wasi/main.wit b/crates/wasi-preview1-component-adapter/wit/deps/wasi/main.wit new file mode 100644 index 000000000000..264dfee8264d --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/wasi/main.wit @@ -0,0 +1 @@ +package unused:main diff --git a/crates/wasi-preview1-component-adapter/wit/deps/wasi/test.wit b/crates/wasi-preview1-component-adapter/wit/deps/wasi/test.wit new file mode 100644 index 000000000000..a362fd4d906e --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/deps/wasi/test.wit @@ -0,0 +1,19 @@ +// only used as part of `test-programs` +world test-reactor { + + import wasi:cli-base/environment + import wasi:io/streams + import wasi:cli-base/preopens + import wasi:filesystem/filesystem + import wasi:cli-base/exit + + export add-strings: func(s: list) -> u32 + export get-strings: func() -> list + + use wasi:io/streams.{output-stream} + + export write-strings-to: func(o: output-stream) -> result + + use wasi:filesystem/filesystem.{descriptor-stat} + export pass-an-imported-record: func(d: descriptor-stat) -> string +} diff --git a/crates/wasi-preview1-component-adapter/wit/main.wit b/crates/wasi-preview1-component-adapter/wit/main.wit new file mode 100644 index 000000000000..264dfee8264d --- /dev/null +++ b/crates/wasi-preview1-component-adapter/wit/main.wit @@ -0,0 +1 @@ +package unused:main diff --git a/crates/wasi-preview1-component-adapter/wit/reactor.wit b/crates/wasi-preview1-component-adapter/wit/reactor.wit deleted file mode 100644 index fb6b1ac9647c..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/reactor.wit +++ /dev/null @@ -1,26 +0,0 @@ -default world reactor { - import wall-clock: clocks.wall-clock - import monotonic-clock: clocks.monotonic-clock - import timezone: clocks.timezone - import filesystem: filesystem.filesystem - import instance-network: sockets.instance-network - import ip-name-lookup: sockets.ip-name-lookup - import network: sockets.network - import tcp-create-socket: sockets.tcp-create-socket - import tcp: sockets.tcp - import udp-create-socket: sockets.udp-create-socket - import udp: sockets.udp - import random: random.random - import insecure-random: random.insecure - import insecure-random-seed: random.insecure-seed - import poll: poll.poll - import streams: io.streams - import console: logging.handler - import default-outgoing-HTTP: http.outgoing-handler - import environment: wasi-cli-base.environment - import preopens: wasi-cli-base.preopens - import stdin: wasi-cli-base.stdio.stdin - import stdout: wasi-cli-base.stdio.stdout - import stderr: wasi-cli-base.stdio.stderr - import exit: wasi-cli-base.exit -}