diff --git a/examples/middleware.py b/examples/middleware.py index 77209a0..3dacddd 100644 --- a/examples/middleware.py +++ b/examples/middleware.py @@ -1,5 +1,4 @@ from socketify import App, middleware -import inspect async def get_user(authorization): if authorization: @@ -30,4 +29,6 @@ def home(res, req, user=None): app = App() app.get("/", middleware(auth, another_middie, home)) app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) -app.run() \ No newline at end of file +app.run() + +#You can also take a loop on MiddlewareRouter in middleware_router.py ;) \ No newline at end of file diff --git a/examples/middleware_router.py b/examples/middleware_router.py new file mode 100644 index 0000000..01696c7 --- /dev/null +++ b/examples/middleware_router.py @@ -0,0 +1,46 @@ +from socketify import App, MiddlewareRouter, middleware + + +async def get_user(authorization): + if authorization: + #you can do something async here + return { 'greeting': 'Hello, World' } + return None + +async def auth(res, req, data=None): + user = await get_user(req.get_header('authorization')) + if not user: + res.write_status(403).end("not authorized") + #returning Falsy in middlewares just stop the execution of the next middleware + return False + + #returns extra data + return user + +def another_middie(res, req, data=None): + #now we can mix sync and async and change the data here + if isinstance(data, dict): + gretting = data.get('greeting', '') + data['greeting'] = f"{gretting} from another middie ;)" + return data + +def home(res, req, user=None): + res.cork_end(user.get('greeting', None)) + + + +app = App() + +#you can use an Middleware router to add middlewares to every route you set +auth_router = MiddlewareRouter(app, auth) +auth_router.get("/", home) +#you can also mix middleware() with MiddlewareRouter +auth_router.get("/another", middleware(another_middie, home)) + +#you can also pass multiple middlewares on the MiddlewareRouter +other_router = MiddlewareRouter(app, auth, another_middie) +other_router.get("/another_way", home) + + +app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) +app.run() \ No newline at end of file diff --git a/src/socketify/__init__.py b/src/socketify/__init__.py index ced0b45..4267860 100644 --- a/src/socketify/__init__.py +++ b/src/socketify/__init__.py @@ -1,2 +1,2 @@ -from .socketify import App, AppOptions, AppListenOptions, OpCode, SendStatus, CompressOptions, middleware -from .helpers import sendfile \ No newline at end of file +from .socketify import App, AppOptions, AppListenOptions, OpCode, SendStatus, CompressOptions +from .helpers import sendfile, middleware, MiddlewareRouter \ No newline at end of file diff --git a/src/socketify/helpers.py b/src/socketify/helpers.py index 773b136..9e9c240 100644 --- a/src/socketify/helpers.py +++ b/src/socketify/helpers.py @@ -1,6 +1,7 @@ import os import time import mimetypes +import inspect from os import path mimetypes.init() @@ -103,4 +104,92 @@ def static_route(app, route, directory): res.run_async(sendfile(res, req, filename)) if route.startswith("/"): route = route[1::] - app.get("%s/*" % route, route_handler) \ No newline at end of file + app.get("%s/*" % route, route_handler) + + + +def middleware(*functions): + #we use Optional data=None at the end so you can use and middleware inside a middleware + async def middleware_route(res, req, data=None): + some_async_as_run = False + #cicle to all middlewares + for function in functions: + #detect if is coroutine or not + if inspect.iscoroutinefunction(function): + #in async query string, arguments and headers are only valid until the first await + if not some_async_as_run: + #get_headers will preserve headers (and cookies) inside req, after await + headers = req.get_headers() + #get_parameters will preserve all params inside req after await + params = req.get_parameters() + #get queries will preserve all queries inside req after await + queries = req.get_queries() + #mark to only grab header, params and queries one time + some_async_as_run = True + data = await function(res, req, data) + else: + #call middlewares + data = function(res, req, data) + #stops if returns Falsy + if not data: + break + + return middleware_route + + +class MiddlewareRouter(): + def __init__(self, app, *middlewares): + self.app = app + self.middlewares = middlewares + + def get(self, path, handler): + middies = list(self.middlewares) + middies.append(handler) + self.app.get(path, middleware(*middies)) + return self + + def post(self, path, handler): + middies = list(self.middlewares) + middies.append(handler) + self.app.post(path, middleware(*middies)) + return self + def options(self, path, handler): + middies = list(self.middlewares) + middies.append(handler) + self.app.options(path, middleware(*middies)) + return self + def delete(self, path, handler): + middies = list(self.middlewares) + middies.append(handler) + self.app.delete(path, middleware(*middies)) + return self + def patch(self, path, handler): + middies = list(self.middlewares) + middies.append(handler) + self.app.patch(path, middleware(*middies)) + return self + def put(self, path, handler): + middies = list(self.middlewares) + middies.append(handler) + self.app.put(path, middleware(*middies)) + return self + def head(self, path, handler): + middies = list(self.middlewares) + middies.append(handler) + self.app.head(path, middleware(*middies)) + return self + def connect(self, path, handler): + middies = list(self.middlewares) + middies.append(handler) + self.app.connect(path, middleware(*middies)) + return self + def trace(self, path, handler): + middies = list(self.middlewares) + middies.append(handler) + self.app.trace(path, middleware(*middies)) + return self + def any(self, path, handler): + middies = list(self.middlewares) + middies.append(handler) + self.app.any(path, middleware(*middies)) + return self \ No newline at end of file diff --git a/src/socketify/socketify.py b/src/socketify/socketify.py index 44a45f9..df58832 100644 --- a/src/socketify/socketify.py +++ b/src/socketify/socketify.py @@ -1825,31 +1825,3 @@ class AppOptions: self.ca_file_name = ca_file_name self.ssl_ciphers = ssl_ciphers self.ssl_prefer_low_memory_usage = ssl_prefer_low_memory_usage - -def middleware(*functions): - async def middleware_route(res, req): - data = None - some_async_as_run = False - #cicle to all middlewares - for function in functions: - #detect if is coroutine or not - if inspect.iscoroutinefunction(function): - #in async query string, arguments and headers are only valid until the first await - if not some_async_as_run: - #get_headers will preserve headers (and cookies) inside req, after await - headers = req.get_headers() - #get_parameters will preserve all params inside req after await - params = req.get_parameters() - #get queries will preserve all queries inside req after await - queries = req.get_queries() - #mark to only grab header, params and queries one time - some_async_as_run = True - data = await function(res, req, data) - else: - #call middlewares - data = function(res, req, data) - #stops if returns Falsy - if not data: - break - - return middleware_route \ No newline at end of file