diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9e841dd..8ec80d0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,12 +4,12 @@ - Python - `pip` -- `componentize-py` 0.16.0 +- `componentize-py` 0.17.2 Once you have `pip` installed, you can install `componentize-py` using: ```bash -pip install componentize-py==0.16.0 +pip install componentize-py==0.17.2 ``` ### Generating the bindings @@ -22,9 +22,11 @@ componentize-py \ -d src/spin_sdk/wit \ -w spin-all \ --import-interface-name fermyon:spin/postgres@2.0.0=postgres \ + --import-interface-name spin:postgres/postgres@3.0.0=spin_postgres_postgres \ + --import-interface-name fermyon:spin/sqlite@2.0.0=sqlite \ + --world-module spin_sdk.wit \ bindings \ - bindings \ - --world-module spin_sdk.wit + bindings rm -r src/spin_sdk/wit/imports src/spin_sdk/wit/exports mv bindings/spin_sdk/wit/* src/spin_sdk/wit/ rm -r bindings diff --git a/README.md b/README.md index f3da2e1..f202c6e 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ enter a virtual environment and then install the desired packages ```shell python -m venv .venv source .venv/bin/activate -pip install componentize-py==0.16.0 spin-sdk==3.3.1 mypy==1.8.0 +pip install componentize-py==0.17.2 spin-sdk==3.4.1 mypy==1.8.0 ``` ### Hello, World diff --git a/docs/v3/http/index.html b/docs/v3/http/index.html index 3db7af2..50f5070 100644 --- a/docs/v3/http/index.html +++ b/docs/v3/http/index.html @@ -3,19 +3,30 @@
- +def send(request: Request) -> Response:
+ """Send an HTTP request and return a response or raise an error"""
+ loop = PollLoop()
+ asyncio.set_event_loop(loop)
+ return loop.run_until_complete(send_async(request))
+Send an HTTP request and return a response or raise an error
async def send_and_close(sink: Sink,
data: bytes)
async def send_and_close(sink: Sink, data: bytes):
+ await sink.send(data)
+ sink.close()
+
async def send_async(request: Request) ‑> Response
async def send_async(request: Request) -> Response:
+ match request.method:
+ case "GET":
+ method: Method = Method_Get()
+ case "HEAD":
+ method = Method_Head()
+ case "POST":
+ method = Method_Post()
+ case "PUT":
+ method = Method_Put()
+ case "DELETE":
+ method = Method_Delete()
+ case "CONNECT":
+ method = Method_Connect()
+ case "OPTIONS":
+ method = Method_Options()
+ case "TRACE":
+ method = Method_Trace()
+ case "PATCH":
+ method = Method_Patch()
+ case _:
+ method = Method_Other(request.method)
+
+ url_parsed = parse.urlparse(request.uri)
+
+ match url_parsed.scheme:
+ case "http":
+ scheme: Scheme = Scheme_Http()
+ case "https":
+ scheme = Scheme_Https()
+ case "":
+ scheme = Scheme_Http()
+ case _:
+ scheme = Scheme_Other(url_parsed.scheme)
+
+ headers_dict = request.headers
+
+ # Add a `content-length` header if the caller didn't include one, but did
+ # specify a body:
+ if headers_dict.get('content-length') is None:
+ content_length = len(request.body) if request.body is not None else 0
+ # Make a copy rather than mutate in place, since the caller might not
+ # expect us to mutate it:
+ headers_dict = headers_dict.copy()
+ headers_dict['content-length'] = str(content_length)
+
+ headers = list(map(
+ lambda pair: (pair[0], bytes(pair[1], "utf-8")),
+ headers_dict.items()
+ ))
+
+ outgoing_request = OutgoingRequest(Fields.from_list(headers))
+ outgoing_request.set_method(method)
+ outgoing_request.set_scheme(scheme)
+ if url_parsed.netloc == '':
+ if scheme == "http":
+ authority = ":80"
+ else:
+ authority = ":443"
+ else:
+ authority = url_parsed.netloc
+
+ outgoing_request.set_authority(authority)
+
+ path_and_query = url_parsed.path
+ if url_parsed.query:
+ path_and_query += '?' + url_parsed.query
+ outgoing_request.set_path_with_query(path_and_query)
+
+ outgoing_body = request.body if request.body is not None else bytearray()
+ sink = Sink(outgoing_request.body())
+ incoming_response: IncomingResponse = (await asyncio.gather(
+ poll_loop.send(outgoing_request),
+ send_and_close(sink, outgoing_body)
+ ))[0]
+
+ response_body = Stream(incoming_response.consume())
+ body = bytearray()
+ while True:
+ chunk = await response_body.next()
+ if chunk is None:
+ headers = incoming_response.headers()
+ simple_response = Response(
+ incoming_response.status(),
+ dict(map(
+ lambda pair: (pair[0], str(pair[1], "utf-8")),
+ headers.entries()
+ )),
+ bytes(body)
+ )
+ headers.__exit__(None, None, None)
+ incoming_response.__exit__(None, None, None)
+ return simple_response
+ else:
+ body += chunk
+Simplified handler for incoming HTTP requests using blocking, buffered I/O.
class IncomingHandler(exports.IncomingHandler):
+class IncomingHandler(Base):
"""Simplified handler for incoming HTTP requests using blocking, buffered I/O."""
-
+
def handle_request(self, request: Request) -> Response:
"""Handle an incoming HTTP request and return a response or raise an error"""
raise NotImplementedError
-
+
def handle(self, request: IncomingRequest, response_out: ResponseOutparam):
method = request.method()
@@ -164,6 +292,7 @@ Classes
response_stream.__exit__(None, None, None)
OutgoingBody.finish(response_body, None)
Simplified handler for incoming HTTP requests using blocking, buffered I/O.
def handle_request(self, request: Request) -> Response:
+ """Handle an incoming HTTP request and return a response or raise an error"""
+ raise NotImplementedError
+Handle an incoming HTTP request and return a response or raise an error
An HTTP request
An HTTP request
var body : bytes | NoneAn HTTP response
An HTTP response
var body : bytes | NoneRespo