forked from sparckles/Robyn
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmod.rs
135 lines (123 loc) · 4.33 KB
/
mod.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#[deny(clippy::if_same_then_else)]
/// This is the module that has all the executor functions
/// i.e. the functions that have the responsibility of parsing and executing functions.
pub mod web_socket_executors;
use std::sync::Arc;
use anyhow::Result;
use log::debug;
use pyo3::prelude::*;
use pyo3_asyncio::TaskLocals;
use crate::types::{
function_info::FunctionInfo, request::Request, response::Response, MiddlewareReturn,
};
#[inline]
fn get_function_output<'a, T>(
function: &'a FunctionInfo,
py: Python<'a>,
function_args: &T,
) -> Result<&'a PyAny, PyErr>
where
T: ToPyObject,
{
let handler = function.handler.as_ref(py);
// kwargs are handled
let kwargs = function.kwargs.as_ref(py);
let function_args = function_args.to_object(py);
match function.number_of_params {
0 => handler.call0(),
1 => {
if function.args.as_ref(py).get_item("request").is_some()
|| function.args.as_ref(py).get_item("response").is_some()
{
// If 'request' is present, call handler with 'function_args'
handler.call1((function_args,))
} else {
// If neither 'request' nor 'response' is present
handler.call((), Some(kwargs))
}
}
2 => {
if function.args.as_ref(py).get_item("request").is_some()
|| function.args.as_ref(py).get_item("response").is_some()
{
// If either 'request' or 'response' is present, call handler with 'function_args' and 'kwargs'
handler.call((function_args,), Some(kwargs))
} else {
// If neither 'request' nor 'response' is present
handler.call((), Some(kwargs))
}
}
3..=u8::MAX => handler.call((function_args,), Some(kwargs)),
}
}
// Execute the middleware function
// type T can be either Request (before middleware) or Response (after middleware)
// Return type can either be a Request or a Response, we wrap it inside an enum for easier handling
#[inline]
pub async fn execute_middleware_function<T>(
input: &T,
function: &FunctionInfo,
) -> Result<MiddlewareReturn>
where
T: for<'a> FromPyObject<'a> + ToPyObject,
{
if function.is_async {
let output: Py<PyAny> = Python::with_gil(|py| {
pyo3_asyncio::tokio::into_future(get_function_output(function, py, input)?)
})?
.await?;
Python::with_gil(|py| -> Result<MiddlewareReturn> {
let output_response = output.extract::<Response>(py);
match output_response {
Ok(o) => Ok(MiddlewareReturn::Response(o)),
Err(_) => Ok(MiddlewareReturn::Request(output.extract::<Request>(py)?)),
}
})
} else {
Python::with_gil(|py| -> Result<MiddlewareReturn> {
let output = get_function_output(function, py, input)?;
match output.extract::<Response>() {
Ok(o) => Ok(MiddlewareReturn::Response(o)),
Err(_) => Ok(MiddlewareReturn::Request(output.extract::<Request>()?)),
}
})
}
}
#[inline]
pub async fn execute_http_function(
request: &Request,
function: &FunctionInfo,
) -> PyResult<Response> {
if function.is_async {
let output = Python::with_gil(|py| {
let function_output = get_function_output(function, py, request)?;
pyo3_asyncio::tokio::into_future(function_output)
})?
.await?;
return Python::with_gil(|py| -> PyResult<Response> { output.extract(py) });
};
Python::with_gil(|py| -> PyResult<Response> {
get_function_output(function, py, request)?.extract()
})
}
pub async fn execute_event_handler(
event_handler: Option<Arc<FunctionInfo>>,
task_locals: &TaskLocals,
) -> Result<()> {
if let Some(function) = event_handler {
if function.is_async {
debug!("Startup event handler async");
Python::with_gil(|py| {
pyo3_asyncio::into_future_with_locals(
task_locals,
function.handler.as_ref(py).call0()?,
)
})?
.await?;
} else {
debug!("Startup event handler");
Python::with_gil(|py| function.handler.call0(py))?;
}
}
Ok(())
}