From fa463e21fd1422b361da5e55fced5f096e90d438 Mon Sep 17 00:00:00 2001 From: Sanskar Jethi Date: Mon, 31 Jan 2022 22:21:59 +0000 Subject: [PATCH 1/9] Add middlewares --- src/lib.rs | 1 + src/middleware_router.rs | 119 +++++++++++++++++++++++++++++++++++++++ src/server.rs | 19 +++++++ 3 files changed, 139 insertions(+) create mode 100644 src/middleware_router.rs diff --git a/src/lib.rs b/src/lib.rs index e62184a2c..33d1d1349 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +mod middleware_router; mod processor; mod router; mod server; diff --git a/src/middleware_router.rs b/src/middleware_router.rs new file mode 100644 index 000000000..c9757df39 --- /dev/null +++ b/src/middleware_router.rs @@ -0,0 +1,119 @@ +use std::collections::HashMap; +use std::sync::{Arc, RwLock}; +// pyo3 modules +use crate::types::PyFunction; +use pyo3::prelude::*; +use pyo3::types::PyAny; + +use actix_web::http::Method; +use matchit::Node; + +/// Contains the thread safe hashmaps of different routes + +pub struct MiddlewareRouter { + get_routes: RwLock>, + post_routes: RwLock>, + put_routes: RwLock>, + delete_routes: RwLock>, + patch_routes: RwLock>, + head_routes: RwLock>, + options_routes: RwLock>, + connect_routes: RwLock>, + trace_routes: RwLock>, +} + +impl MiddlewareRouter { + pub fn new() -> Self { + Self { + get_routes: RwLock::new(Node::new()), + post_routes: RwLock::new(Node::new()), + put_routes: RwLock::new(Node::new()), + delete_routes: RwLock::new(Node::new()), + patch_routes: RwLock::new(Node::new()), + head_routes: RwLock::new(Node::new()), + options_routes: RwLock::new(Node::new()), + connect_routes: RwLock::new(Node::new()), + trace_routes: RwLock::new(Node::new()), + } + } + + #[inline] + fn get_relevant_map(&self, route: Method) -> Option<&RwLock>> { + match route { + Method::GET => Some(&self.get_routes), + Method::POST => Some(&self.post_routes), + Method::PUT => Some(&self.put_routes), + Method::PATCH => Some(&self.patch_routes), + Method::DELETE => Some(&self.delete_routes), + Method::HEAD => Some(&self.head_routes), + Method::OPTIONS => Some(&self.options_routes), + Method::CONNECT => Some(&self.connect_routes), + Method::TRACE => Some(&self.trace_routes), + _ => None, + } + } + + #[inline] + fn get_relevant_map_str(&self, route: &str) -> Option<&RwLock>> { + if route != "WS" { + let method = match Method::from_bytes(route.as_bytes()) { + Ok(res) => res, + Err(_) => return None, + }; + + return self.get_relevant_map(method); + } else { + return None; + } + } + + // Checks if the functions is an async function + // Inserts them in the router according to their nature(CoRoutine/SyncFunction) + pub fn add_route( + &self, + route_type: &str, // we can just have route type as WS + route: &str, + handler: Py, + is_async: bool, + number_of_params: u8, + ) { + let table = match self.get_relevant_map_str(route_type) { + Some(table) => table, + None => return, + }; + + let function = if is_async { + PyFunction::CoRoutine(handler) + } else { + PyFunction::SyncFunction(handler) + }; + + table + .write() + .unwrap() + .insert(route.to_string(), (function, number_of_params)) + .unwrap(); + } + + pub fn get_route( + &self, + route_method: Method, + route: &str, // check for the route method here + ) -> Option<((PyFunction, u8), HashMap)> { + // need to split this function in multiple smaller functions + let table = self.get_relevant_map(route_method)?; + + match table.read().unwrap().at(route) { + Ok(res) => { + let mut route_params = HashMap::new(); + + for (key, value) in res.params.iter() { + route_params.insert(key.to_string(), value.to_string()); + } + + Some((res.value.clone(), route_params)) + } + Err(_) => None, + } + } +} diff --git a/src/server.rs b/src/server.rs index e533756bf..0081b3546 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,3 +1,4 @@ +use crate::middleware_router::MiddlewareRouter; use crate::processor::{apply_headers, execute_event_handler, handle_request}; use crate::router::Router; use crate::shared_socket::SocketHeld; @@ -32,6 +33,7 @@ struct Directory { #[pyclass] pub struct Server { router: Arc, + middleware_router: Arc, headers: Arc>, directories: Arc>>, startup_handler: Option, @@ -44,6 +46,7 @@ impl Server { pub fn new() -> Self { Self { router: Arc::new(Router::new()), + middleware_router: Arc::new(MiddlewareRouter::new()), headers: Arc::new(DashMap::new()), directories: Arc::new(RwLock::new(Vec::new())), startup_handler: None, @@ -71,6 +74,7 @@ impl Server { let raw_socket = held_socket.get_socket(); let router = self.router.clone(); + let middleware_router = self.middleware_router.clone(); let headers = self.headers.clone(); let directories = self.directories.clone(); let workers = Arc::new(workers); @@ -124,6 +128,7 @@ impl Server { app = app .app_data(web::Data::new(router.clone())) + .app_data(web::Data::new(middleware_router.clone())) .app_data(web::Data::new(headers.clone())); let web_socket_map = router_copy.get_web_socket_map(); @@ -223,6 +228,20 @@ impl Server { .add_route(route_type, route, handler, is_async, number_of_params); } + /// Add a new route to the routing tables + /// can be called after the server has been started + pub fn add_middleware_route( + &self, + route_type: &str, + route: &str, + handler: Py, + is_async: bool, + number_of_params: u8, + ) { + println!("Route added for {} {} ", route_type, route); + self.middleware_router .add_route(route_type, route, handler, is_async, number_of_params); + } + /// Add a new web socket route to the routing tables /// can be called after the server has been started pub fn add_web_socket_route( From b80d142b718fcc0bf25d986e4dbf11023a227652 Mon Sep 17 00:00:00 2001 From: Sanskar Jethi Date: Tue, 1 Feb 2022 21:37:54 +0000 Subject: [PATCH 2/9] Modularise some code --- robyn/__init__.py | 37 ++++++++++- robyn/processpool.py | 7 ++- src/lib.rs | 3 +- src/{ => routers}/middleware_router.rs | 16 ++--- src/routers/mod.rs | 3 + src/{ => routers}/router.rs | 2 +- src/routers/web_socket_router.rs | 85 ++++++++++++++++++++++++++ src/server.rs | 7 ++- 8 files changed, 142 insertions(+), 18 deletions(-) rename src/{ => routers}/middleware_router.rs (91%) create mode 100644 src/routers/mod.rs rename src/{ => routers}/router.rs (99%) create mode 100644 src/routers/web_socket_router.rs diff --git a/robyn/__init__.py b/robyn/__init__.py index cb21d0123..83f519da2 100644 --- a/robyn/__init__.py +++ b/robyn/__init__.py @@ -35,8 +35,9 @@ def __init__(self, file_object): self.routes = [] self.headers = [] self.routes = [] - self.directories = [] + self.middlewares = [] self.web_sockets = {} + self.directories = [] self.event_handlers = {} def add_route(self, route_type, endpoint, handler): @@ -61,6 +62,40 @@ def add_route(self, route_type, endpoint, handler): ) ) + def add_middleware_route(self, route_type, endpoint, handler): + """ + [This is base handler for the middleware decorator] + + :param route_type [str]: [??] + :param endpoint [str]: [endpoint for the route added] + :param handler [function]: [represents the sync or async function passed as a handler for the route] + """ + + """ We will add the status code here only + """ + number_of_params = len(signature(handler).parameters) + self.routes.append( + ( + route_type, + endpoint, + handler, + asyncio.iscoroutinefunction(handler), + number_of_params, + ) + ) + + def before_request(self, endpoint): + """ + [The @app.before_request decorator to add a get route] + + :param endpoint [str]: [endpoint to server the route] + """ + + def inner(handler): + self.add_middleware_route("BEFORE_REQUEST", endpoint, handler) + + return inner + def add_directory( self, route, directory_path, index_file=None, show_files_listing=False ): diff --git a/robyn/processpool.py b/robyn/processpool.py index fec6d82eb..88f96c469 100644 --- a/robyn/processpool.py +++ b/robyn/processpool.py @@ -12,7 +12,7 @@ def spawn_process( - directories, headers, routes, web_sockets, event_handlers, socket, workers + directories, headers, routes, middlewares, web_sockets, event_handlers, socket, workers ): """ This function is called by the main process handler to create a server runtime. @@ -21,6 +21,7 @@ def spawn_process( :param directories tuple: the list of all the directories and related data in a tuple :param headers tuple: All the global headers in a tuple :param routes tuple: The routes touple, containing the description about every route. + :param middlewares tuple: The middleware router touple, containing the description about every route. :param web_sockets list: This is a list of all the web socket routes :param event_handlers Dict: This is an event dict that contains the event handlers :param socket Socket: This is the main tcp socket, which is being shared across multiple processes. @@ -53,6 +54,10 @@ def spawn_process( route_type, endpoint, handler, is_async, number_of_params = route server.add_route(route_type, endpoint, handler, is_async, number_of_params) + for route in middlewares: + route_type, endpoint, handler, is_async, number_of_params = route + server.add_middleware_route(route_type, endpoint, handler, is_async, number_of_params) + if "startup" in event_handlers: server.add_startup_handler(event_handlers[Events.STARTUP][0], event_handlers[Events.STARTUP][1]) diff --git a/src/lib.rs b/src/lib.rs index 33d1d1349..5eafb9db1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ -mod middleware_router; mod processor; -mod router; +mod routers; mod server; mod shared_socket; mod types; diff --git a/src/middleware_router.rs b/src/routers/middleware_router.rs similarity index 91% rename from src/middleware_router.rs rename to src/routers/middleware_router.rs index c9757df39..76046cdb1 100644 --- a/src/middleware_router.rs +++ b/src/routers/middleware_router.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::sync::{Arc, RwLock}; +use std::sync::RwLock; // pyo3 modules use crate::types::PyFunction; use pyo3::prelude::*; @@ -55,16 +55,12 @@ impl MiddlewareRouter { #[inline] fn get_relevant_map_str(&self, route: &str) -> Option<&RwLock>> { - if route != "WS" { - let method = match Method::from_bytes(route.as_bytes()) { - Ok(res) => res, - Err(_) => return None, - }; + let method = match Method::from_bytes(route.as_bytes()) { + Ok(res) => res, + Err(_) => return None, + }; - return self.get_relevant_map(method); - } else { - return None; - } + return self.get_relevant_map(method); } // Checks if the functions is an async function diff --git a/src/routers/mod.rs b/src/routers/mod.rs new file mode 100644 index 000000000..51bbe14e1 --- /dev/null +++ b/src/routers/mod.rs @@ -0,0 +1,3 @@ +pub mod middleware_router; +pub mod router; +pub mod web_socket_router; diff --git a/src/router.rs b/src/routers/router.rs similarity index 99% rename from src/router.rs rename to src/routers/router.rs index cd7f5da20..9c3fd5692 100644 --- a/src/router.rs +++ b/src/routers/router.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::sync::{Arc, RwLock}; +use std::sync::RwLock; // pyo3 modules use crate::types::PyFunction; use pyo3::prelude::*; diff --git a/src/routers/web_socket_router.rs b/src/routers/web_socket_router.rs new file mode 100644 index 000000000..9462a075d --- /dev/null +++ b/src/routers/web_socket_router.rs @@ -0,0 +1,85 @@ +use std::collections::HashMap; +use std::sync::RwLock; +// pyo3 modules +use crate::types::PyFunction; +use pyo3::prelude::*; +use pyo3::types::PyAny; + +use actix_web::http::Method; +use matchit::Node; + +/// Contains the thread safe hashmaps of different routes + +pub struct WebSocketRouter { + web_socket_routes: RwLock>>, +} + +impl WebSocketRouter { + pub fn new() -> Self { + Self { + web_socket_routes: RwLock::new(HashMap::new()), + } + } + + #[inline] + pub fn get_web_socket_map( + &self, + ) -> &RwLock>> { + &self.web_socket_routes + } + + // Checks if the functions is an async function + // Inserts them in the router according to their nature(CoRoutine/SyncFunction) + pub fn add_websocket_route( + &self, + route: &str, + connect_route: (Py, bool, u8), + close_route: (Py, bool, u8), + message_route: (Py, bool, u8), + ) { + let table = self.get_web_socket_map(); + let (connect_route_function, connect_route_is_async, connect_route_params) = connect_route; + let (close_route_function, close_route_is_async, close_route_params) = close_route; + let (message_route_function, message_route_is_async, message_route_params) = message_route; + + let insert_in_router = + |handler: Py, is_async: bool, number_of_params: u8, socket_type: &str| { + let function = if is_async { + PyFunction::CoRoutine(handler) + } else { + PyFunction::SyncFunction(handler) + }; + + println!("socket type is {:?} {:?}", table, route); + + table + .write() + .unwrap() + .entry(route.to_string()) + .or_default() + .insert(socket_type.to_string(), (function, number_of_params)) + }; + + insert_in_router( + connect_route_function, + connect_route_is_async, + connect_route_params, + "connect", + ); + + insert_in_router( + close_route_function, + close_route_is_async, + close_route_params, + "close", + ); + + insert_in_router( + message_route_function, + message_route_is_async, + message_route_params, + "message", + ); + } + +} diff --git a/src/server.rs b/src/server.rs index 0081b3546..3938d9a06 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,6 +1,6 @@ -use crate::middleware_router::MiddlewareRouter; use crate::processor::{apply_headers, execute_event_handler, handle_request}; -use crate::router::Router; +use crate::routers::middleware_router::MiddlewareRouter; +use crate::routers::router::Router; use crate::shared_socket::SocketHeld; use crate::types::{Headers, PyFunction}; use crate::web_socket_connection::start_web_socket; @@ -239,7 +239,8 @@ impl Server { number_of_params: u8, ) { println!("Route added for {} {} ", route_type, route); - self.middleware_router .add_route(route_type, route, handler, is_async, number_of_params); + self.middleware_router + .add_route(route_type, route, handler, is_async, number_of_params); } /// Add a new web socket route to the routing tables From 4e79e1150139b44b54a3334c51f440649acf3acc Mon Sep 17 00:00:00 2001 From: Sanskar Jethi Date: Thu, 3 Feb 2022 23:46:41 +0000 Subject: [PATCH 3/9] Refactor the routers --- robyn/__init__.py | 1 + src/processor.rs | 3 ++ src/routers/router.rs | 61 -------------------------------- src/routers/web_socket_router.rs | 4 --- src/server.rs | 26 +++++++++----- 5 files changed, 21 insertions(+), 74 deletions(-) diff --git a/robyn/__init__.py b/robyn/__init__.py index 83f519da2..321eef156 100644 --- a/robyn/__init__.py +++ b/robyn/__init__.py @@ -138,6 +138,7 @@ def start(self, url="127.0.0.1", port=5000): self.directories, self.headers, self.routes, + [], self.web_sockets, self.event_handlers, copied_socket, diff --git a/src/processor.rs b/src/processor.rs index 52f47e54b..793d38cab 100644 --- a/src/processor.rs +++ b/src/processor.rs @@ -92,6 +92,9 @@ async fn execute_http_function( queries: HashMap<&str, &str>, number_of_params: u8, ) -> Result { + // TODO: + // try executing the first version of middleware(s) here + // with just headers as params let mut data: Option> = None; if req.method() == Method::POST diff --git a/src/routers/router.rs b/src/routers/router.rs index 9c3fd5692..ebf0ead11 100644 --- a/src/routers/router.rs +++ b/src/routers/router.rs @@ -20,7 +20,6 @@ pub struct Router { options_routes: RwLock>, connect_routes: RwLock>, trace_routes: RwLock>, - web_socket_routes: RwLock>>, } impl Router { @@ -35,7 +34,6 @@ impl Router { options_routes: RwLock::new(Node::new()), connect_routes: RwLock::new(Node::new()), trace_routes: RwLock::new(Node::new()), - web_socket_routes: RwLock::new(HashMap::new()), } } @@ -55,13 +53,6 @@ impl Router { } } - #[inline] - pub fn get_web_socket_map( - &self, - ) -> &RwLock>> { - &self.web_socket_routes - } - #[inline] fn get_relevant_map_str(&self, route: &str) -> Option<&RwLock>> { if route != "WS" { @@ -106,58 +97,6 @@ impl Router { // Checks if the functions is an async function // Inserts them in the router according to their nature(CoRoutine/SyncFunction) - pub fn add_websocket_route( - &self, - route: &str, - connect_route: (Py, bool, u8), - close_route: (Py, bool, u8), - message_route: (Py, bool, u8), - ) { - let table = self.get_web_socket_map(); - let (connect_route_function, connect_route_is_async, connect_route_params) = connect_route; - let (close_route_function, close_route_is_async, close_route_params) = close_route; - let (message_route_function, message_route_is_async, message_route_params) = message_route; - - let insert_in_router = - |handler: Py, is_async: bool, number_of_params: u8, socket_type: &str| { - let function = if is_async { - PyFunction::CoRoutine(handler) - } else { - PyFunction::SyncFunction(handler) - }; - - println!("socket type is {:?} {:?}", table, route); - - table - .write() - .unwrap() - .entry(route.to_string()) - .or_default() - .insert(socket_type.to_string(), (function, number_of_params)) - }; - - insert_in_router( - connect_route_function, - connect_route_is_async, - connect_route_params, - "connect", - ); - - insert_in_router( - close_route_function, - close_route_is_async, - close_route_params, - "close", - ); - - insert_in_router( - message_route_function, - message_route_is_async, - message_route_params, - "message", - ); - } - pub fn get_route( &self, route_method: Method, diff --git a/src/routers/web_socket_router.rs b/src/routers/web_socket_router.rs index 9462a075d..e1c6632f1 100644 --- a/src/routers/web_socket_router.rs +++ b/src/routers/web_socket_router.rs @@ -5,9 +5,6 @@ use crate::types::PyFunction; use pyo3::prelude::*; use pyo3::types::PyAny; -use actix_web::http::Method; -use matchit::Node; - /// Contains the thread safe hashmaps of different routes pub struct WebSocketRouter { @@ -81,5 +78,4 @@ impl WebSocketRouter { "message", ); } - } diff --git a/src/server.rs b/src/server.rs index 3938d9a06..3e7d5e11e 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,6 +1,6 @@ use crate::processor::{apply_headers, execute_event_handler, handle_request}; -use crate::routers::middleware_router::MiddlewareRouter; use crate::routers::router::Router; +use crate::routers::{middleware_router::MiddlewareRouter, web_socket_router::WebSocketRouter}; use crate::shared_socket::SocketHeld; use crate::types::{Headers, PyFunction}; use crate::web_socket_connection::start_web_socket; @@ -33,6 +33,7 @@ struct Directory { #[pyclass] pub struct Server { router: Arc, + websocket_router: Arc, middleware_router: Arc, headers: Arc>, directories: Arc>>, @@ -40,12 +41,17 @@ pub struct Server { shutdown_handler: Option, } +fn test_function(req: HttpRequest) -> HttpRequest { + return req; +} + #[pymethods] impl Server { #[new] pub fn new() -> Self { Self { router: Arc::new(Router::new()), + websocket_router: Arc::new(WebSocketRouter::new()), middleware_router: Arc::new(MiddlewareRouter::new()), headers: Arc::new(DashMap::new()), directories: Arc::new(RwLock::new(Vec::new())), @@ -75,6 +81,7 @@ impl Server { let router = self.router.clone(); let middleware_router = self.middleware_router.clone(); + let web_socket_router = self.websocket_router.clone(); let headers = self.headers.clone(); let directories = self.directories.clone(); let workers = Arc::new(workers); @@ -101,7 +108,6 @@ impl Server { let mut app = App::new(); let event_loop_hdl = copied_event_loop.clone(); let directories = directories.read().unwrap(); - let router_copy = router.clone(); // this loop matches three types of directory serving // 1. Serves a build folder. e.g. the build folder generated from yarn build @@ -131,7 +137,7 @@ impl Server { .app_data(web::Data::new(middleware_router.clone())) .app_data(web::Data::new(headers.clone())); - let web_socket_map = router_copy.get_web_socket_map(); + let web_socket_map = web_socket_router.get_web_socket_map(); for (elem, value) in (web_socket_map.read().unwrap()).iter() { let route = elem.clone(); let params = value.clone(); @@ -154,11 +160,13 @@ impl Server { ); } - app.default_service(web::route().to(move |router, headers, payload, req| { - pyo3_asyncio::tokio::scope_local(event_loop_hdl.clone(), async move { - index(router, headers, payload, req).await - }) - })) + app.default_service(web::route().to( + move |router, headers, payload, mut req| { + pyo3_asyncio::tokio::scope_local(event_loop_hdl.clone(), async move { + index(router, headers, payload, req).await + }) + }, + )) }) .keep_alive(KeepAlive::Os) .workers(*workers.clone()) @@ -253,7 +261,7 @@ impl Server { close_route: (Py, bool, u8), message_route: (Py, bool, u8), ) { - self.router + self.websocket_router .add_websocket_route(route, connect_route, close_route, message_route); } From ee7198b9873b4abe465171c79f17692c1f253e10 Mon Sep 17 00:00:00 2001 From: Sanskar Jethi Date: Sat, 5 Feb 2022 16:00:33 +0000 Subject: [PATCH 4/9] First version of middleware(s) implemented --- integration_tests/base_routes.py | 11 ++++++- robyn/__init__.py | 5 ++-- src/routers/middleware_router.rs | 49 ++++++-------------------------- src/server.rs | 35 ++++++++++++++++++----- 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/integration_tests/base_routes.py b/integration_tests/base_routes.py index e06f6ca15..cfda60e14 100644 --- a/integration_tests/base_routes.py +++ b/integration_tests/base_routes.py @@ -42,10 +42,19 @@ def message(): async def hello(request): global callCount callCount += 1 - _message = "Called " + str(callCount) + " times" + message = "Called " + str(callCount) + " times" + print(message) return jsonify(request) +@app.before_request("/") +async def hello_before_request(request): + global callCount + callCount += 1 + print(request) + return "" + + @app.get("/test/:id") async def test(request): print(request) diff --git a/robyn/__init__.py b/robyn/__init__.py index 321eef156..ec3716153 100644 --- a/robyn/__init__.py +++ b/robyn/__init__.py @@ -74,7 +74,7 @@ def add_middleware_route(self, route_type, endpoint, handler): """ We will add the status code here only """ number_of_params = len(signature(handler).parameters) - self.routes.append( + self.middlewares.append( ( route_type, endpoint, @@ -130,6 +130,7 @@ def start(self, url="127.0.0.1", port=5000): if not self.dev: workers = self.workers socket = SocketHeld(url, port) + print(self.middlewares) for _ in range(self.processes): copied_socket = socket.try_clone() p = Process( @@ -138,7 +139,7 @@ def start(self, url="127.0.0.1", port=5000): self.directories, self.headers, self.routes, - [], + self.middlewares, self.web_sockets, self.event_handlers, copied_socket, diff --git a/src/routers/middleware_router.rs b/src/routers/middleware_router.rs index 76046cdb1..17095443c 100644 --- a/src/routers/middleware_router.rs +++ b/src/routers/middleware_router.rs @@ -11,58 +11,27 @@ use matchit::Node; /// Contains the thread safe hashmaps of different routes pub struct MiddlewareRouter { - get_routes: RwLock>, - post_routes: RwLock>, - put_routes: RwLock>, - delete_routes: RwLock>, - patch_routes: RwLock>, - head_routes: RwLock>, - options_routes: RwLock>, - connect_routes: RwLock>, - trace_routes: RwLock>, + before_request: RwLock>, + after_request: RwLock>, } impl MiddlewareRouter { pub fn new() -> Self { Self { - get_routes: RwLock::new(Node::new()), - post_routes: RwLock::new(Node::new()), - put_routes: RwLock::new(Node::new()), - delete_routes: RwLock::new(Node::new()), - patch_routes: RwLock::new(Node::new()), - head_routes: RwLock::new(Node::new()), - options_routes: RwLock::new(Node::new()), - connect_routes: RwLock::new(Node::new()), - trace_routes: RwLock::new(Node::new()), + before_request: RwLock::new(Node::new()), + after_request: RwLock::new(Node::new()), } } #[inline] - fn get_relevant_map(&self, route: Method) -> Option<&RwLock>> { + fn get_relevant_map(&self, route: &str) -> Option<&RwLock>> { match route { - Method::GET => Some(&self.get_routes), - Method::POST => Some(&self.post_routes), - Method::PUT => Some(&self.put_routes), - Method::PATCH => Some(&self.patch_routes), - Method::DELETE => Some(&self.delete_routes), - Method::HEAD => Some(&self.head_routes), - Method::OPTIONS => Some(&self.options_routes), - Method::CONNECT => Some(&self.connect_routes), - Method::TRACE => Some(&self.trace_routes), + "BEFORE_REQUEST" => Some(&self.before_request), + "AFTER_REQUEST" => Some(&self.after_request), _ => None, } } - #[inline] - fn get_relevant_map_str(&self, route: &str) -> Option<&RwLock>> { - let method = match Method::from_bytes(route.as_bytes()) { - Ok(res) => res, - Err(_) => return None, - }; - - return self.get_relevant_map(method); - } - // Checks if the functions is an async function // Inserts them in the router according to their nature(CoRoutine/SyncFunction) pub fn add_route( @@ -73,7 +42,7 @@ impl MiddlewareRouter { is_async: bool, number_of_params: u8, ) { - let table = match self.get_relevant_map_str(route_type) { + let table = match self.get_relevant_map(route_type) { Some(table) => table, None => return, }; @@ -93,7 +62,7 @@ impl MiddlewareRouter { pub fn get_route( &self, - route_method: Method, + route_method: &str, route: &str, // check for the route method here ) -> Option<((PyFunction, u8), HashMap)> { // need to split this function in multiple smaller functions diff --git a/src/server.rs b/src/server.rs index 3e7d5e11e..7ce091853 100644 --- a/src/server.rs +++ b/src/server.rs @@ -41,10 +41,6 @@ pub struct Server { shutdown_handler: Option, } -fn test_function(req: HttpRequest) -> HttpRequest { - return req; -} - #[pymethods] impl Server { #[new] @@ -161,9 +157,13 @@ impl Server { } app.default_service(web::route().to( - move |router, headers, payload, mut req| { + move |router, + middleware_router: web::Data>, + headers, + payload, + mut req| { pyo3_asyncio::tokio::scope_local(event_loop_hdl.clone(), async move { - index(router, headers, payload, req).await + index(router, middleware_router, headers, payload, req).await }) }, )) @@ -246,7 +246,7 @@ impl Server { is_async: bool, number_of_params: u8, ) { - println!("Route added for {} {} ", route_type, route); + println!("MiddleWare Route added for {} {} ", route_type, route); self.middleware_router .add_route(route_type, route, handler, is_async, number_of_params); } @@ -297,6 +297,7 @@ impl Default for Server { /// path, and returns a Future of a Response. async fn index( router: web::Data>, + middleware_router: web::Data>, headers: web::Data>, mut payload: web::Payload, req: HttpRequest, @@ -311,6 +312,26 @@ async fn index( } } + let _ = match middleware_router.get_route("BEFORE_REQUEST", req.uri().path()) { + Some(((handler_function, number_of_params), route_params)) => { + handle_request( + handler_function, + number_of_params, + &headers, + &mut payload, + &req, + route_params, + queries.clone(), + ) + .await; + } + None => { + let mut response = HttpResponse::Ok(); + apply_headers(&mut response, &headers); + response.finish(); + } + }; + match router.get_route(req.method().clone(), req.uri().path()) { Some(((handler_function, number_of_params), route_params)) => { handle_request( From a3aa2bf9445aec5e0f36d002c5db41ca51d1b0f7 Mon Sep 17 00:00:00 2001 From: Sanskar Jethi Date: Tue, 8 Feb 2022 22:25:33 +0000 Subject: [PATCH 5/9] Middleware support implemented --- robyn/__init__.py | 14 +++++- src/processor.rs | 114 ++++++++++++++++++++++++++++++++++++++++++++-- src/server.rs | 46 ++++++++++++------- 3 files changed, 153 insertions(+), 21 deletions(-) diff --git a/robyn/__init__.py b/robyn/__init__.py index ec3716153..f572ce068 100644 --- a/robyn/__init__.py +++ b/robyn/__init__.py @@ -92,7 +92,19 @@ def before_request(self, endpoint): """ def inner(handler): - self.add_middleware_route("BEFORE_REQUEST", endpoint, handler) + # add handling for async functions + async def async_inner_handler(*args): + await handler(args) + return args + + def inner_handler(*args): + handler(*args) + return args + + if asyncio.iscoroutinefunction(handler): + self.add_middleware_route("BEFORE_REQUEST", endpoint, async_inner_handler) + else: + self.add_middleware_route("BEFORE_REQUEST", endpoint, inner_handler) return inner diff --git a/src/processor.rs b/src/processor.rs index 793d38cab..4f43e726c 100644 --- a/src/processor.rs +++ b/src/processor.rs @@ -7,7 +7,7 @@ use anyhow::{bail, Result}; use crate::types::{Headers, PyFunction}; use futures_util::stream::StreamExt; use pyo3::prelude::*; -use pyo3::types::PyDict; +use pyo3::types::{PyDict, PyTuple}; use std::fs::File; use std::io::Read; @@ -67,6 +67,36 @@ pub async fn handle_request( response.body(contents) } +pub async fn handle_middleware_request( + function: PyFunction, + number_of_params: u8, + headers: &Arc, + payload: &mut web::Payload, + req: &HttpRequest, + route_params: HashMap, + queries: HashMap<&str, &str>, +) -> Py { + let contents = match execute_middleware_function( + function, + payload, + headers, + req, + route_params, + queries, + number_of_params, + ) + .await + { + Ok(res) => res, + Err(err) => Python::with_gil(|py| { + let a: Py = PyTuple::empty(py).into_py(py); + a + }), + }; + + contents +} + // ideally this should be async /// A function to read lossy files and serve it as a html response /// @@ -81,6 +111,78 @@ fn read_file(file_path: &str) -> String { String::from_utf8_lossy(&buf).to_string() } +async fn execute_middleware_function( + function: PyFunction, + payload: &mut web::Payload, + headers: &Headers, + req: &HttpRequest, + route_params: HashMap, + queries: HashMap<&str, &str>, + number_of_params: u8, +) -> Result> { + // TODO: + // try executing the first version of middleware(s) here + // with just headers as params + + // request object accessible while creating routes + let mut request = HashMap::new(); + let mut headers_python = HashMap::new(); + for elem in headers.into_iter() { + headers_python.insert(elem.key().clone(), elem.value().clone()); + } + + match function { + PyFunction::CoRoutine(handler) => { + let output = Python::with_gil(|py| { + let handler = handler.as_ref(py); + request.insert("params", route_params.into_py(py)); + request.insert("queries", queries.into_py(py)); + request.insert("headers", headers_python.into_py(py)); + + // this makes the request object to be accessible across every route + let coro: PyResult<&PyAny> = match number_of_params { + 0 => handler.call0(), + 1 => handler.call1((request,)), + // this is done to accomodate any future params + 2_u8..=u8::MAX => handler.call1((request,)), + }; + pyo3_asyncio::tokio::into_future(coro?) + })?; + + let output = output.await?; + + let res = Python::with_gil(|py| -> PyResult> { + let output: Py = output.extract(py).unwrap(); + Ok(output) + })?; + + Ok(res) + } + + PyFunction::SyncFunction(handler) => { + tokio::task::spawn_blocking(move || { + Python::with_gil(|py| { + let handler = handler.as_ref(py); + request.insert("params", route_params.into_py(py)); + request.insert("headers", headers_python.into_py(py)); + + let output: PyResult<&PyAny> = match number_of_params { + 0 => handler.call0(), + 1 => handler.call1((request,)), + // this is done to accomodate any future params + 2_u8..=u8::MAX => handler.call1((request,)), + }; + + let output: Py = output?.extract().unwrap(); + + Ok(output) + }) + }) + .await? + } + } +} + // Change this! #[inline] async fn execute_http_function( @@ -162,10 +264,13 @@ async fn execute_http_function( res.get_item("response_type").unwrap().extract()?; if response_type == "static_file" { // static file here and serve string - let file_path = res.get_item("file_path").unwrap().extract()?; + let file_path = + res.get_item("file_path").unwrap().extract()?; Ok(read_file(file_path)) } else { - Err(PyErr::from_instance("Server Error".into_py(py).as_ref(py))) + Err(PyErr::from_instance( + "Server Error".into_py(py).as_ref(py), + )) } } false => { @@ -228,7 +333,8 @@ pub async fn execute_event_handler(event_handler: Option, event_loop println!("Startup event handler async"); let coroutine = function.as_ref(py).call0().unwrap(); - pyo3_asyncio::into_future_with_loop(event_loop.as_ref(py), coroutine).unwrap() + pyo3_asyncio::into_future_with_loop(event_loop.as_ref(py), coroutine) + .unwrap() }); future.await.unwrap(); } diff --git a/src/server.rs b/src/server.rs index 7ce091853..6c216e371 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,4 +1,6 @@ -use crate::processor::{apply_headers, execute_event_handler, handle_request}; +use crate::processor::{ + apply_headers, execute_event_handler, handle_middleware_request, handle_request, +}; use crate::routers::router::Router; use crate::routers::{middleware_router::MiddlewareRouter, web_socket_router::WebSocketRouter}; use crate::shared_socket::SocketHeld; @@ -123,8 +125,10 @@ impl Server { .show_files_listing(), ); } else { - app = app - .service(Files::new(&directory.route, &directory.directory_path)); + app = app.service(Files::new( + &directory.route, + &directory.directory_path, + )); } } @@ -162,9 +166,13 @@ impl Server { headers, payload, mut req| { - pyo3_asyncio::tokio::scope_local(event_loop_hdl.clone(), async move { - index(router, middleware_router, headers, payload, req).await - }) + pyo3_asyncio::tokio::scope_local( + event_loop_hdl.clone(), + async move { + index(router, middleware_router, headers, payload, req) + .await + }, + ) }, )) }) @@ -247,8 +255,13 @@ impl Server { number_of_params: u8, ) { println!("MiddleWare Route added for {} {} ", route_type, route); - self.middleware_router - .add_route(route_type, route, handler, is_async, number_of_params); + self.middleware_router.add_route( + route_type, + route, + handler, + is_async, + number_of_params, + ); } /// Add a new web socket route to the routing tables @@ -261,8 +274,12 @@ impl Server { close_route: (Py, bool, u8), message_route: (Py, bool, u8), ) { - self.websocket_router - .add_websocket_route(route, connect_route, close_route, message_route); + self.websocket_router.add_websocket_route( + route, + connect_route, + close_route, + message_route, + ); } /// Add a new startup handler @@ -314,7 +331,7 @@ async fn index( let _ = match middleware_router.get_route("BEFORE_REQUEST", req.uri().path()) { Some(((handler_function, number_of_params), route_params)) => { - handle_request( + let x = handle_middleware_request( handler_function, number_of_params, &headers, @@ -324,12 +341,9 @@ async fn index( queries.clone(), ) .await; + println!("{:?}", x.to_string()); } - None => { - let mut response = HttpResponse::Ok(); - apply_headers(&mut response, &headers); - response.finish(); - } + None => {} }; match router.get_route(req.method().clone(), req.uri().path()) { From 4a66eb0f78f1a81643db94592b1816465c8e3d32 Mon Sep 17 00:00:00 2001 From: Sanskar Jethi Date: Wed, 9 Feb 2022 21:54:35 +0000 Subject: [PATCH 6/9] Add AFTER REQUEST --- integration_tests/base_routes.py | 8 ++++++++ robyn/__init__.py | 24 ++++++++++++++++++++++++ src/server.rs | 27 ++++++++++++++++++++++++--- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/integration_tests/base_routes.py b/integration_tests/base_routes.py index cfda60e14..e148c8e7e 100644 --- a/integration_tests/base_routes.py +++ b/integration_tests/base_routes.py @@ -55,6 +55,14 @@ async def hello_before_request(request): return "" +@app.after_request("/") +async def hello_after_request(request): + global callCount + callCount += 1 + print(request) + return "" + + @app.get("/test/:id") async def test(request): print(request) diff --git a/robyn/__init__.py b/robyn/__init__.py index f572ce068..b2ef394ac 100644 --- a/robyn/__init__.py +++ b/robyn/__init__.py @@ -108,6 +108,30 @@ def inner_handler(*args): return inner + def after_request(self, endpoint): + """ + [The @app.after_request decorator to add a get route] + + :param endpoint [str]: [endpoint to server the route] + """ + + def inner(handler): + # add handling for async functions + async def async_inner_handler(*args): + await handler(args) + return args + + def inner_handler(*args): + handler(*args) + return args + + if asyncio.iscoroutinefunction(handler): + self.add_middleware_route("AFTER_REQUEST", endpoint, async_inner_handler) + else: + self.add_middleware_route("AFTER_REQUEST", endpoint, inner_handler) + + return inner + def add_directory( self, route, directory_path, index_file=None, show_files_listing=False ): diff --git a/src/server.rs b/src/server.rs index 6c216e371..efad11afc 100644 --- a/src/server.rs +++ b/src/server.rs @@ -319,6 +319,8 @@ async fn index( mut payload: web::Payload, req: HttpRequest, ) -> impl Responder { + // cloning hashmaps a lot here + // try reading about arc or rc let mut queries = HashMap::new(); if req.query_string().len() > 0 { @@ -346,7 +348,7 @@ async fn index( None => {} }; - match router.get_route(req.method().clone(), req.uri().path()) { + let response = match router.get_route(req.method().clone(), req.uri().path()) { Some(((handler_function, number_of_params), route_params)) => { handle_request( handler_function, @@ -355,7 +357,7 @@ async fn index( &mut payload, &req, route_params, - queries, + queries.clone(), ) .await } @@ -364,5 +366,24 @@ async fn index( apply_headers(&mut response, &headers); response.finish() } - } + }; + + let _ = match middleware_router.get_route("AFTER_REQUEST", req.uri().path()) { + Some(((handler_function, number_of_params), route_params)) => { + let x = handle_middleware_request( + handler_function, + number_of_params, + &headers, + &mut payload, + &req, + route_params, + queries.clone(), + ) + .await; + println!("{:?}", x.to_string()); + } + None => {} + }; + + response } From ccbc9cddd9d414d539acc1c05afcf995dbe56e97 Mon Sep 17 00:00:00 2001 From: Sanskar Jethi Date: Fri, 11 Feb 2022 15:51:59 +0000 Subject: [PATCH 7/9] Add arcs --- src/processor.rs | 16 ++++++------ src/server.rs | 48 ++++++++++++++---------------------- src/web_socket_connection.rs | 10 +++++--- 3 files changed, 32 insertions(+), 42 deletions(-) diff --git a/src/processor.rs b/src/processor.rs index 4f43e726c..06aa83384 100644 --- a/src/processor.rs +++ b/src/processor.rs @@ -264,13 +264,10 @@ async fn execute_http_function( res.get_item("response_type").unwrap().extract()?; if response_type == "static_file" { // static file here and serve string - let file_path = - res.get_item("file_path").unwrap().extract()?; + let file_path = res.get_item("file_path").unwrap().extract()?; Ok(read_file(file_path)) } else { - Err(PyErr::from_instance( - "Server Error".into_py(py).as_ref(py), - )) + Err(PyErr::from_instance("Server Error".into_py(py).as_ref(py))) } } false => { @@ -319,9 +316,12 @@ async fn execute_http_function( } } -pub async fn execute_event_handler(event_handler: Option, event_loop: Py) { +pub async fn execute_event_handler( + event_handler: Option>, + event_loop: Arc>, +) { match event_handler { - Some(handler) => match handler { + Some(handler) => match &(*handler) { PyFunction::SyncFunction(function) => { println!("Startup event handler"); Python::with_gil(|py| { @@ -333,7 +333,7 @@ pub async fn execute_event_handler(event_handler: Option, event_loop println!("Startup event handler async"); let coroutine = function.as_ref(py).call0().unwrap(); - pyo3_asyncio::into_future_with_loop(event_loop.as_ref(py), coroutine) + pyo3_asyncio::into_future_with_loop((*event_loop).as_ref(py), coroutine) .unwrap() }); future.await.unwrap(); diff --git a/src/server.rs b/src/server.rs index efad11afc..11145df3f 100644 --- a/src/server.rs +++ b/src/server.rs @@ -39,8 +39,8 @@ pub struct Server { middleware_router: Arc, headers: Arc>, directories: Arc>>, - startup_handler: Option, - shutdown_handler: Option, + startup_handler: Option>, + shutdown_handler: Option>, } #[pymethods] @@ -90,8 +90,8 @@ impl Server { asyncio .call_method1("set_event_loop", (event_loop,)) .unwrap(); - let event_loop_hdl = PyObject::from(event_loop); - let event_loop_cleanup = PyObject::from(event_loop); + let event_loop_hdl = Arc::new(PyObject::from(event_loop)); + let event_loop_cleanup = event_loop_hdl.clone(); let startup_handler = self.startup_handler.clone(); let shutdown_handler = self.shutdown_handler.clone(); @@ -125,10 +125,8 @@ impl Server { .show_files_listing(), ); } else { - app = app.service(Files::new( - &directory.route, - &directory.directory_path, - )); + app = app + .service(Files::new(&directory.route, &directory.directory_path)); } } @@ -165,12 +163,11 @@ impl Server { middleware_router: web::Data>, headers, payload, - mut req| { + req| { pyo3_asyncio::tokio::scope_local( - event_loop_hdl.clone(), + (*event_loop_hdl).clone(), async move { - index(router, middleware_router, headers, payload, req) - .await + index(router, middleware_router, headers, payload, req).await }, ) }, @@ -187,7 +184,7 @@ impl Server { }); }); - let event_loop = event_loop.call_method0("run_forever"); + let event_loop = (*event_loop).call_method0("run_forever"); if event_loop.is_err() { println!("Ctrl c handler"); Python::with_gil(|py| { @@ -255,13 +252,8 @@ impl Server { number_of_params: u8, ) { println!("MiddleWare Route added for {} {} ", route_type, route); - self.middleware_router.add_route( - route_type, - route, - handler, - is_async, - number_of_params, - ); + self.middleware_router + .add_route(route_type, route, handler, is_async, number_of_params); } /// Add a new web socket route to the routing tables @@ -274,20 +266,16 @@ impl Server { close_route: (Py, bool, u8), message_route: (Py, bool, u8), ) { - self.websocket_router.add_websocket_route( - route, - connect_route, - close_route, - message_route, - ); + self.websocket_router + .add_websocket_route(route, connect_route, close_route, message_route); } /// Add a new startup handler pub fn add_startup_handler(&mut self, handler: Py, is_async: bool) { println!("Adding startup handler"); match is_async { - true => self.startup_handler = Some(PyFunction::CoRoutine(handler)), - false => self.startup_handler = Some(PyFunction::SyncFunction(handler)), + true => self.startup_handler = Some(Arc::new(PyFunction::CoRoutine(handler))), + false => self.startup_handler = Some(Arc::new(PyFunction::SyncFunction(handler))), }; println!("{:?}", self.startup_handler); } @@ -296,8 +284,8 @@ impl Server { pub fn add_shutdown_handler(&mut self, handler: Py, is_async: bool) { println!("Adding shutdown handler"); match is_async { - true => self.shutdown_handler = Some(PyFunction::CoRoutine(handler)), - false => self.shutdown_handler = Some(PyFunction::SyncFunction(handler)), + true => self.shutdown_handler = Some(Arc::new(PyFunction::CoRoutine(handler))), + false => self.shutdown_handler = Some(Arc::new(PyFunction::SyncFunction(handler))), }; println!("{:?}", self.startup_handler); println!("{:?}", self.shutdown_handler); diff --git a/src/web_socket_connection.rs b/src/web_socket_connection.rs index 1517a1c93..c2182c22d 100644 --- a/src/web_socket_connection.rs +++ b/src/web_socket_connection.rs @@ -8,17 +8,18 @@ use actix_web_actors::ws::WebsocketContext; use pyo3::prelude::*; use std::collections::HashMap; +use std::sync::Arc; /// Define HTTP actor #[derive(Clone)] struct MyWs { router: HashMap, - event_loop: PyObject, + event_loop: Arc, } fn execute_ws_functionn( handler_function: &PyFunction, - event_loop: PyObject, + event_loop: Arc, ctx: &mut ws::WebsocketContext, ws: &MyWs, ) { @@ -34,7 +35,8 @@ fn execute_ws_functionn( let fut = Python::with_gil(|py| { let handler = handler.as_ref(py); let coro = handler.call0().unwrap(); - pyo3_asyncio::into_future_with_loop(event_loop.as_ref(py), coro).unwrap() + pyo3_asyncio::into_future_with_loop((*(event_loop.clone())).as_ref(py), coro) + .unwrap() }); let f = async move { let output = fut.await.unwrap(); @@ -117,7 +119,7 @@ pub async fn start_web_socket( req: HttpRequest, stream: web::Payload, router: HashMap, - event_loop: PyObject, + event_loop: Arc, ) -> Result { // execute the async function here let resp = ws::start( From f2f5bb511665ccded8f1143a61e4deaa145ead2b Mon Sep 17 00:00:00 2001 From: Sanskar Jethi Date: Sun, 13 Feb 2022 19:54:50 +0000 Subject: [PATCH 8/9] Add body params --- src/processor.rs | 40 ++++++++++++++++++++++++++++++---------- src/server.rs | 2 +- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/processor.rs b/src/processor.rs index 06aa83384..7d84e52e9 100644 --- a/src/processor.rs +++ b/src/processor.rs @@ -40,7 +40,7 @@ pub async fn handle_request( payload: &mut web::Payload, req: &HttpRequest, route_params: HashMap, - queries: HashMap<&str, &str>, + queries: HashMap, ) -> HttpResponse { let contents = match execute_http_function( function, @@ -74,7 +74,7 @@ pub async fn handle_middleware_request( payload: &mut web::Payload, req: &HttpRequest, route_params: HashMap, - queries: HashMap<&str, &str>, + queries: HashMap, ) -> Py { let contents = match execute_middleware_function( function, @@ -89,8 +89,8 @@ pub async fn handle_middleware_request( { Ok(res) => res, Err(err) => Python::with_gil(|py| { - let a: Py = PyTuple::empty(py).into_py(py); - a + println!("{:?}", err); + PyTuple::empty(py).into_py(py) }), }; @@ -111,19 +111,39 @@ fn read_file(file_path: &str) -> String { String::from_utf8_lossy(&buf).to_string() } -async fn execute_middleware_function( +async fn execute_middleware_function<'a>( function: PyFunction, payload: &mut web::Payload, headers: &Headers, req: &HttpRequest, route_params: HashMap, - queries: HashMap<&str, &str>, + queries: HashMap, number_of_params: u8, ) -> Result> { // TODO: // try executing the first version of middleware(s) here // with just headers as params + let mut data: Option> = None; + + if req.method() == Method::POST + || req.method() == Method::PUT + || req.method() == Method::PATCH + || req.method() == Method::DELETE + { + let mut body = web::BytesMut::new(); + while let Some(chunk) = payload.next().await { + let chunk = chunk?; + // limit max size of in-memory payload + if (body.len() + chunk.len()) > MAX_SIZE { + bail!("Body content Overflow"); + } + body.extend_from_slice(&chunk); + } + + data = Some(body.to_vec()) + } + // request object accessible while creating routes let mut request = HashMap::new(); let mut headers_python = HashMap::new(); @@ -138,6 +158,7 @@ async fn execute_middleware_function( request.insert("params", route_params.into_py(py)); request.insert("queries", queries.into_py(py)); request.insert("headers", headers_python.into_py(py)); + request.insert("body", data.into_py(py)); // this makes the request object to be accessible across every route let coro: PyResult<&PyAny> = match number_of_params { @@ -164,7 +185,9 @@ async fn execute_middleware_function( Python::with_gil(|py| { let handler = handler.as_ref(py); request.insert("params", route_params.into_py(py)); + request.insert("queries", queries.into_py(py)); request.insert("headers", headers_python.into_py(py)); + request.insert("body", data.into_py(py)); let output: PyResult<&PyAny> = match number_of_params { 0 => handler.call0(), @@ -191,12 +214,9 @@ async fn execute_http_function( headers: &Headers, req: &HttpRequest, route_params: HashMap, - queries: HashMap<&str, &str>, + queries: HashMap, number_of_params: u8, ) -> Result { - // TODO: - // try executing the first version of middleware(s) here - // with just headers as params let mut data: Option> = None; if req.method() == Method::POST diff --git a/src/server.rs b/src/server.rs index 11145df3f..680b2d9c8 100644 --- a/src/server.rs +++ b/src/server.rs @@ -315,7 +315,7 @@ async fn index( let split = req.query_string().split("&"); for s in split { let params = s.split_once("=").unwrap_or((s, "")); - queries.insert(params.0, params.1); + queries.insert(params.0.to_string(), params.1.to_string()); } } From c77745d015e990bf51879c16d7cb0ec7e8aaa3aa Mon Sep 17 00:00:00 2001 From: Sanskar Jethi Date: Mon, 14 Feb 2022 19:52:20 +0000 Subject: [PATCH 9/9] Add comments for decorator --- robyn/__init__.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/robyn/__init__.py b/robyn/__init__.py index b2ef394ac..936c0f826 100644 --- a/robyn/__init__.py +++ b/robyn/__init__.py @@ -91,8 +91,12 @@ def before_request(self, endpoint): :param endpoint [str]: [endpoint to server the route] """ + # This inner function is basically a wrapper arround the closure(decorator) + # being returned. + # It takes in a handler and converts it in into a closure + # and returns the arguments. + # Arguments are returned as they could be modified by the middlewares. def inner(handler): - # add handling for async functions async def async_inner_handler(*args): await handler(args) return args @@ -115,8 +119,12 @@ def after_request(self, endpoint): :param endpoint [str]: [endpoint to server the route] """ + # This inner function is basically a wrapper arround the closure(decorator) + # being returned. + # It takes in a handler and converts it in into a closure + # and returns the arguments. + # Arguments are returned as they could be modified by the middlewares. def inner(handler): - # add handling for async functions async def async_inner_handler(*args): await handler(args) return args