Skip to content

Commit 38145b9

Browse files
committed
define spin_http module in Rust
This avoids duplication and paves the way for calling back into Rust from Python. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
1 parent 1ae67a4 commit 38145b9

2 files changed

Lines changed: 45 additions & 42 deletions

File tree

py/spin_http.py

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/lib.rs

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,54 +4,64 @@ use {
44
anyhow::{Error, Result},
55
http::{header::HeaderName, HeaderValue},
66
once_cell::unsync::OnceCell,
7-
pyo3::{FromPyObject, IntoPy, PyErr, PyObject, Python},
7+
pyo3::{types::PyModule, PyObject, PyResult, Python},
88
spin_sdk::http::{Request, Response},
99
std::{ops::Deref, str},
1010
};
1111

1212
thread_local! {
13-
static REQUEST: OnceCell<PyObject> = OnceCell::new();
1413
static HANDLE_REQUEST: OnceCell<PyObject> = OnceCell::new();
1514
}
1615

17-
struct HttpRequest<'a> {
18-
method: &'a str,
19-
uri: &'a str,
20-
headers: Vec<(&'a str, &'a str)>,
16+
#[pyo3::pyclass]
17+
#[pyo3(name = "Request")]
18+
struct HttpRequest {
19+
#[pyo3(get)]
20+
method: String,
21+
#[pyo3(get)]
22+
uri: String,
23+
#[pyo3(get)]
24+
headers: Vec<(String, String)>,
2125
// todo: this should be a byte slice, but make sure it gets converted to/from Python correctly
22-
body: Option<&'a str>,
23-
}
24-
25-
impl IntoPy<PyObject> for HttpRequest<'_> {
26-
fn into_py(self, py: Python<'_>) -> PyObject {
27-
REQUEST.with(|cell| {
28-
cell.get()
29-
.unwrap()
30-
.call1(py, (self.method, self.uri, self.headers, self.body))
31-
.unwrap()
32-
})
33-
}
26+
#[pyo3(get)]
27+
body: Option<String>,
3428
}
3529

36-
#[derive(FromPyObject)]
30+
#[derive(Clone)]
31+
#[pyo3::pyclass]
32+
#[pyo3(name = "Response")]
3733
struct HttpResponse {
3834
status: u16,
3935
headers: Vec<(String, String)>,
4036
// todo: this should be a byte slice, but make sure it gets converted to/from Python correctly
4137
body: Option<String>,
4238
}
4339

40+
#[pyo3::pymethods]
41+
impl HttpResponse {
42+
#[new]
43+
fn new(status: u16, headers: Vec<(String, String)>, body: Option<String>) -> Self {
44+
Self {
45+
status,
46+
headers,
47+
body,
48+
}
49+
}
50+
}
51+
52+
#[pyo3::pymodule]
53+
#[pyo3(name = "spin_http")]
54+
fn spin_http_module(_py: Python<'_>, module: &PyModule) -> PyResult<()> {
55+
module.add_class::<HttpRequest>()?;
56+
module.add_class::<HttpResponse>()
57+
}
58+
4459
fn do_init() -> Result<()> {
60+
pyo3::append_to_inittab!(spin_http_module);
61+
4562
pyo3::prepare_freethreaded_python();
4663

4764
Python::with_gil(|py| {
48-
REQUEST.with(|cell| {
49-
cell.set(py.import("spin_http")?.getattr("Request")?.into())
50-
.unwrap();
51-
52-
Ok::<_, PyErr>(())
53-
})?;
54-
5565
HANDLE_REQUEST.with(|cell| {
5666
cell.set(py.import("app")?.getattr("handle_request")?.into())
5767
.unwrap();
@@ -72,17 +82,22 @@ pub extern "C" fn init() {
7282
fn handle(request: Request) -> Result<Response> {
7383
let uri = request.uri().to_string();
7484
let request = HttpRequest {
75-
method: request.method().as_str(),
76-
uri: &uri,
85+
method: request.method().as_str().to_owned(),
86+
uri,
7787
headers: request
7888
.headers()
7989
.iter()
80-
.map(|(k, v)| Ok((k.as_str(), str::from_utf8(v.as_bytes())?)))
90+
.map(|(k, v)| {
91+
Ok((
92+
k.as_str().to_owned(),
93+
str::from_utf8(v.as_bytes())?.to_owned(),
94+
))
95+
})
8196
.collect::<Result<_>>()?,
8297
body: request
8398
.body()
8499
.as_ref()
85-
.map(|bytes| Ok::<_, Error>(str::from_utf8(bytes)?))
100+
.map(|bytes| Ok::<_, Error>(str::from_utf8(bytes)?.to_owned()))
86101
.transpose()?,
87102
};
88103

0 commit comments

Comments
 (0)