diff --git a/examples/python/INSTRUCTIONS b/examples/python/INSTRUCTIONS index 1809f0a..4d9063c 100644 --- a/examples/python/INSTRUCTIONS +++ b/examples/python/INSTRUCTIONS @@ -1,6 +1,6 @@ See the documentation about installing tooling: https://learn.golem.cloud/docs/python-language-guide/setup Generate bindings from WIT: - componentize-py bindings bindings + componentize-py -d ./wit -w component-name bindings bindings Package the Python code into a WASM component: - componentize-py componentize main -o component_name.wasm + componentize-py -d ./wit -w component-name componentize main -o component_name.wasm diff --git a/examples/python/python-default-wasi-http/.gitignore b/examples/python/python-default-wasi-http/.gitignore new file mode 100644 index 0000000..775da38 --- /dev/null +++ b/examples/python/python-default-wasi-http/.gitignore @@ -0,0 +1,4 @@ +bindings +component_name.wasm +wit-generated +__pycache__ diff --git a/examples/python/python-default-wasi-http/main.py b/examples/python/python-default-wasi-http/main.py new file mode 100644 index 0000000..63062f3 --- /dev/null +++ b/examples/python/python-default-wasi-http/main.py @@ -0,0 +1,63 @@ +import asyncio +import poll_loop + +from component_name import exports +from component_name.types import Ok +from component_name.imports import types +from component_name.imports.types import ( + Method_Get, + Method_Post, + Scheme, + Scheme_Http, + Scheme_Https, + Scheme_Other, + IncomingRequest, + ResponseOutparam, + OutgoingResponse, + Fields, + OutgoingBody, + OutgoingRequest, +) +from poll_loop import Stream, Sink, PollLoop +from typing import Tuple +from urllib import parse + +# see https://github.com/bytecodealliance/componentize-py/tree/main/examples/http for a full example. + +class IncomingHandler(exports.IncomingHandler): + """Implements the wasi:http/incoming-handler""" + + def handle(self, request: IncomingRequest, response_out: ResponseOutparam) -> None: + """Handle the specified `request`, sending the response to `response_out`.""" + # Dispatch the request using `asyncio`, backed by a custom event loop + # based on WASI's `poll_oneoff` function. + loop = PollLoop() + asyncio.set_event_loop(loop) + loop.run_until_complete(handle_async(request, response_out)) + + +async def handle_async( + request: IncomingRequest, response_out: ResponseOutparam +) -> None: + """Handle the specified `request`, sending the response to `response_out`.""" + + method = request.method() + path = request.path_with_query() + headers = request.headers().entries() + + if isinstance(method, Method_Get) and path == "/hello": + response = OutgoingResponse(Fields.from_list([])) + + response_body = response.body() + + ResponseOutparam.set(response_out, Ok(response)) + + sink = Sink(response_body) + await sink.send(bytes(f"Hello from python", "utf-8")) + sink.close() + else: + response = OutgoingResponse(Fields.from_list([])) + response.set_status_code(400) + body = response.body() + ResponseOutparam.set(response_out, Ok(response)) + OutgoingBody.finish(body, None) diff --git a/examples/python/python-default-wasi-http/metadata.json b/examples/python/python-default-wasi-http/metadata.json new file mode 100644 index 0000000..85807e6 --- /dev/null +++ b/examples/python/python-default-wasi-http/metadata.json @@ -0,0 +1,13 @@ +{ + "description": "A Golem worker implementing wasi:http/incoming-handler. For use with the http-handler api gateway binding type", + "requiresAdapter": false, + "requiresGolemHostWIT": true, + "requiresWASI": true, + "instructions": "INSTRUCTIONS", + "exclude": [ + "component_name.wasm", + "bindings", + "wit-generated ", + "__pycache__" + ] +} diff --git a/examples/python/python-default-wasi-http/wit/component-name.wit b/examples/python/python-default-wasi-http/wit/component-name.wit new file mode 100644 index 0000000..3c027f5 --- /dev/null +++ b/examples/python/python-default-wasi-http/wit/component-name.wit @@ -0,0 +1,12 @@ +package pack:name; + +// See https://component-model.bytecodealliance.org/design/wit.html for more details about the WIT syntax +// See https://github.com/WebAssembly/wasi-http for an introduction to wasi-http + +world component-name { + // Always required due to a limitation of the bindings generation in componentize-py. + // This import will fail if removed https://github.com/bytecodealliance/componentize-py/blob/c50822c825b4333ff41a0ea3cd9e0c9bc3df49da/bundled/poll_loop.py#L15 + import wasi:http/outgoing-handler@0.2.0; + + export wasi:http/incoming-handler@0.2.0; +}