Last active
December 7, 2023 11:06
-
-
Save Iyusuf40/e902f12a95448162bce07e2b1d198bc7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
class Manager: | |
""" | |
Manages the call flow, serves as the midware manager | |
""" | |
def __init__(self): | |
self.__list = L_List() | |
self.req = {"req value": 0} | |
self.res = {"res value": 0} | |
def register(self, func): | |
node = Node(func) | |
self.__list.insert_node(node) | |
def run_call(self): | |
""" | |
run_call: starts the call flow from the top of the linked list | |
it then transfer flow to the functions themselves to decide wether | |
to call the next function or terminate flow | |
""" | |
node = self.__list.front | |
node.call(self.req, self.res, node.next_wrapper) | |
class L_List: | |
""" | |
A simple linked_list implementation | |
""" | |
def __init__(self): | |
# __last holds reference to the tail end of the list | |
# this is a way to prevent traversing the list from the head to get to the | |
# tail before new node is inserted, makes insertion O(1) | |
self.__last = None | |
self.__front = None # head of the list | |
@property | |
def front(self): | |
return self.__front | |
@property | |
def last(self): | |
return self.__last | |
def insert_node(self, node): | |
if self.__last: # at least a node exists | |
self.__last.set_next(node) # make previous last node second to last | |
if not self.__front: # first node inserted will alway be first, in order insertion :) | |
self.__front = node | |
self.__last = node # make new node last node | |
def get_len(self): | |
count = 0 | |
node = self.__front | |
while node: | |
count += 1 | |
node = node.get_next() | |
return count | |
class Node: | |
""" | |
Nodes of the L_List class | |
""" | |
def __init__(self, func=None): | |
self.__next = None | |
self.__func = func | |
self.req = None | |
self.res = None | |
def set_next(self, node): | |
self.__next = node | |
def get_next(self): | |
return self.__next | |
def call(self, req, res, _next): | |
if self.__func: | |
self.req = req # hold reference to req and res object so as to pass to next | |
self.res = res | |
self.__func(req, res, _next) | |
def next_wrapper(self): | |
""" | |
next_wrapper is the main implementer of next, i.e. next_wrapper is passed as | |
the third arg to the function registered, and the user may decide to call it | |
in order to call the next function in the list or not call it and prevent | |
further functions down the list from being called | |
""" | |
next = self.get_next() | |
if next: | |
next.call(self.req, self.res, next.next_wrapper) | |
if __name__ == "__main__": | |
def func_1(req, res, nxt): | |
print('\nfunc_1 called') | |
prev = req["req value"] | |
req["req value"] += 15 | |
print(f'request modified in func1, prev req value: {prev}, new req {req}\n') | |
nxt() | |
def func_2(req, res, nxt): | |
print('\nfunc_2 called') | |
prev = req["req value"] | |
req["req value"] -= 7 | |
print(f'request modified again in func2, prev req value: {prev}, new req {req}\n') | |
nxt() | |
def func_3(req, res, nxt): | |
print('\nfunc_3 called') | |
prev = req["req value"] | |
req["req value"] -= 7 | |
print(f'request modified again in func3, prev req value: {prev}, new req {req}\n' | |
'and oops func_4, Im greedy, you d never get called\n' | |
) | |
# nxt() # next not called, call sequence terminates here | |
def func_4(req, res, nxt): | |
print('\nfunc_4 called') | |
prev = req["req value"] | |
req["req value"] -= 1 | |
print('oops I was never called') | |
nxt() | |
manager = Manager() | |
manager.register(func_1) | |
manager.register(func_2) | |
manager.register(func_3) | |
manager.register(func_4) | |
manager.run_call() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A very good Implementation of middlewares for frameworks