Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ http-rewriter = { git = "https://github.com/platformatic/http-rewriter" }
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { version = "3", default-features = false, features = ["napi4", "tokio_rt", "async"], optional = true }
napi-derive = { version = "3", optional = true }
pyo3 = { version = "0.26.0", features = ["experimental-async"] }
pyo3-async-runtimes = { version = "0.26.0", features = ["tokio-runtime"] }
pyo3 = { version = "0.27.2", features = ["experimental-async"] }
pyo3-async-runtimes = { version = "0.27.0", features = ["tokio-runtime"] }
thiserror = "2.0.12"
tokio = { version = "1.45.1", features = ["full"] }
libc = "0.2"
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"version": "napi version"
},
"optionalDependencies": {
"@platformatic/python-node-darwin-arm64": "^0.1.4",
"@platformatic/python-node-linux-x64-gnu": "^0.1.4"
"@platformatic/python-node-darwin-arm64": "^2.0.0",
"@platformatic/python-node-linux-x64-gnu": "^2.0.0"
}
}
20 changes: 10 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions scripts/update-version.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,10 @@ import { readFile, writeFile } from 'fs/promises'
const version = process.argv[2].replace(/^v/, '')
const packageJson = JSON.parse(await readFile('package.json', 'utf8'))
packageJson.version = version
// Update platform-specific deps to match release version
for (const dep of Object.keys(packageJson.optionalDependencies)) {
if (dep.startsWith(packageJson.name)) {
packageJson.optionalDependencies[dep] = `^${version}`
}
}
await writeFile('package.json', JSON.stringify(packageJson, null, 2))
17 changes: 10 additions & 7 deletions src/asgi/http.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use http_handler::{Request, RequestExt, Version};
use pyo3::Borrowed;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3::types::{PyAny, PyDict};
Expand Down Expand Up @@ -295,9 +296,11 @@ pub enum HttpSendMessage {
},
}

impl<'py> FromPyObject<'py> for HttpSendMessage {
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
let dict = ob.downcast::<PyDict>()?;
impl<'a, 'py> FromPyObject<'a, 'py> for HttpSendMessage {
type Error = PyErr;

fn extract(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
let dict = ob.cast::<PyDict>()?;
let message_type = dict
.get_item("type")?
.ok_or_else(|| PyValueError::new_err("Missing 'type' key in HTTP send message dictionary"))?;
Expand All @@ -318,22 +321,22 @@ impl<'py> FromPyObject<'py> for HttpSendMessage {

// Convert headers from list of lists to vec of tuples
let mut headers: Vec<(String, String)> = Vec::new();
if let Ok(headers_list) = headers_py.downcast::<pyo3::types::PyList>() {
if let Ok(headers_list) = headers_py.cast::<pyo3::types::PyList>() {
for item in headers_list.iter() {
if let Ok(header_pair) = item.downcast::<pyo3::types::PyList>()
if let Ok(header_pair) = item.cast::<pyo3::types::PyList>()
&& header_pair.len() == 2
{
let name = header_pair.get_item(0)?;
let value = header_pair.get_item(1)?;

// Convert bytes to string
let name_str = if let Ok(bytes) = name.downcast::<pyo3::types::PyBytes>() {
let name_str = if let Ok(bytes) = name.cast::<pyo3::types::PyBytes>() {
String::from_utf8_lossy(bytes.as_bytes()).to_string()
} else {
name.extract::<String>()?
};

let value_str = if let Ok(bytes) = value.downcast::<pyo3::types::PyBytes>() {
let value_str = if let Ok(bytes) = value.cast::<pyo3::types::PyBytes>() {
String::from_utf8_lossy(bytes.as_bytes()).to_string()
} else {
value.extract::<String>()?
Expand Down
7 changes: 5 additions & 2 deletions src/asgi/http_method.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::convert::Infallible;
use std::str::FromStr;

use pyo3::Borrowed;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3::types::PyString;
Expand All @@ -20,8 +21,10 @@ pub enum HttpMethod {
Connect,
}

impl<'py> FromPyObject<'py> for HttpMethod {
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
impl<'a, 'py> FromPyObject<'a, 'py> for HttpMethod {
type Error = PyErr;

fn extract(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
let method: String = ob.extract()?;
method
.to_uppercase()
Expand Down
7 changes: 5 additions & 2 deletions src/asgi/http_version.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::convert::Infallible;
use std::str::FromStr;

use pyo3::Borrowed;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3::types::PyString;
Expand All @@ -14,8 +15,10 @@ pub enum HttpVersion {
V2_0,
}

impl<'py> FromPyObject<'py> for HttpVersion {
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
impl<'a, 'py> FromPyObject<'a, 'py> for HttpVersion {
type Error = PyErr;

fn extract(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
let version: String = ob.extract()?;
match version.as_str() {
"1" | "1.0" => Ok(HttpVersion::V1_0),
Expand Down
9 changes: 6 additions & 3 deletions src/asgi/info.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use pyo3::Borrowed;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3::types::PyDict;
Expand Down Expand Up @@ -35,9 +36,11 @@ impl<'py> IntoPyObject<'py> for AsgiInfo {
}
}

impl<'py> FromPyObject<'py> for AsgiInfo {
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
let dict = ob.downcast::<PyDict>()?;
impl<'a, 'py> FromPyObject<'a, 'py> for AsgiInfo {
type Error = PyErr;

fn extract(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
let dict = ob.cast::<PyDict>()?;
let version: String = dict
.get_item("version")?
.ok_or_else(|| PyValueError::new_err("Missing 'version' key in ASGI info dictionary"))?
Expand Down
9 changes: 6 additions & 3 deletions src/asgi/lifespan.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use pyo3::Borrowed;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3::types::PyDict;
Expand Down Expand Up @@ -67,9 +68,11 @@ pub enum LifespanSendMessage {
}

// Only ever converted from Python to Rust.
impl<'py> FromPyObject<'py> for LifespanSendMessage {
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
let dict = ob.downcast::<PyDict>()?;
impl<'a, 'py> FromPyObject<'a, 'py> for LifespanSendMessage {
type Error = PyErr;

fn extract(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
let dict = ob.cast::<PyDict>()?;
let message_type = dict.get_item("type")?.ok_or_else(|| {
PyValueError::new_err("Missing 'type' key in Lifespan send message dictionary")
})?;
Expand Down
15 changes: 4 additions & 11 deletions src/asgi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,7 @@ async fn forward_http_request<R>(
{
const BUFFER_SIZE: usize = 64 * 1024; // 64KB buffer
let mut buffer = BytesMut::with_capacity(BUFFER_SIZE);
loop {
let n = match request_stream.read_buf(&mut buffer).await {
Ok(n) => n,
Err(_) => break,
};

while let Ok(n) = request_stream.read_buf(&mut buffer).await {
if n == 0 {
// EOF - send final message
let _ = rx.send(HttpReceiveMessage::Request {
Expand Down Expand Up @@ -271,11 +266,9 @@ where
}

// Write body data if not empty
if !body.is_empty() {
if response_stream.write_all(&body).await.is_err() {
// Client disconnected
return true;
}
if !body.is_empty() && response_stream.write_all(&body).await.is_err() {
// Client disconnected
return true;
}

// Check if this was the final chunk
Expand Down
6 changes: 3 additions & 3 deletions src/asgi/sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl Sender {
let args_dict = args.bind(py);
match &self.0 {
SenderType::Http(tx) => {
let msg = HttpSendMessage::extract_bound(args_dict)?;
let msg: HttpSendMessage = args_dict.extract()?;
tx.send(AcknowledgedMessage {
message: msg,
ack: ack_tx,
Expand All @@ -70,7 +70,7 @@ impl Sender {
Ok(())
}
SenderType::WebSocket(tx) => {
let msg = WebSocketSendMessage::extract_bound(args_dict)?;
let msg: WebSocketSendMessage = args_dict.extract()?;
tx.send(AcknowledgedMessage {
message: msg,
ack: ack_tx,
Expand All @@ -79,7 +79,7 @@ impl Sender {
Ok(())
}
SenderType::Lifespan(tx) => {
let msg = LifespanSendMessage::extract_bound(args_dict)?;
let msg: LifespanSendMessage = args_dict.extract()?;
tx.send(AcknowledgedMessage {
message: msg,
ack: ack_tx,
Expand Down
9 changes: 6 additions & 3 deletions src/asgi/websocket.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use http_handler::{Request, RequestExt, Version};
use pyo3::Borrowed;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3::types::PyDict;
Expand Down Expand Up @@ -313,9 +314,11 @@ pub enum WebSocketSendMessage {
},
}

impl<'py> FromPyObject<'py> for WebSocketSendMessage {
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
let dict = ob.downcast::<PyDict>()?;
impl<'a, 'py> FromPyObject<'a, 'py> for WebSocketSendMessage {
type Error = PyErr;

fn extract(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
let dict = ob.cast::<PyDict>()?;
let message_type = dict.get_item("type")?.ok_or_else(|| {
PyValueError::new_err("Missing 'type' key in WebSocket send message dictionary")
})?;
Expand Down
Loading