Skip to content

Instantly share code, notes, and snippets.

@Iyusuf40
Last active December 7, 2023 11:06
Show Gist options
  • Save Iyusuf40/e902f12a95448162bce07e2b1d198bc7 to your computer and use it in GitHub Desktop.
Save Iyusuf40/e902f12a95448162bce07e2b1d198bc7 to your computer and use it in GitHub Desktop.
#!/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()
@Theocode12
Copy link

A very good Implementation of middlewares for frameworks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment