# Path: rep0st/framework/decorator.py
# class DecoratorProcessor(ABC):
# 
#   @abstractmethod
#   def process(self, bindings: List[Any]) -> None:
#     pass
# 
#   def methods_by_decorated_name(
#       self, bindings: List[Any],
#       search_name: str) -> Iterator[Tuple[Type, T, Callable[[Any], Any]]]:
#     for binding in bindings:
#       interface = binding
#       for name, fun in inspect.getmembers(interface):
#         data = getattr(fun, '__' + search_name + '__', None)
#         if data is not None:
#           yield (interface, data, fun)
# 
#   @staticmethod
#   def wrap_function(instance: Any, fun: Callable,
#                     injector: Injector) -> Callable:
#     fun = types.MethodType(fun, instance)
# 
#     @functools.wraps(fun)
#     def wrapper(*args: Any, **kwargs: Any) -> Any:
#       return injector.call_with_injection(
#           callable=fun, args=args, kwargs=kwargs)
# 
#     return wrapper  # type: ignore
# 
# Path: rep0st/framework/execute.py
# def execute(order: float = 0) -> Any:
# 
#   def decorator(function: Any):
#     function.__execute__ = _ExecuteConfiguration(order)
#     return function
# 
#   return decorator
# 
# Path: rep0st/framework/signal_handler.py
# def on_shutdown() -> Any:
# 
#   def decorator(function: Any):
#     function.__on_shutdown__ = _OnShutdownConfiguration()
#     return function
# 
#   return decorator


import logging
import random
import threading
import time
from abc import ABC
from threading import Thread
from typing import Any, Callable, Collection, List, NamedTuple, NewType, Union
from absl import flags
from cheroot.wsgi import Server as WSGIServer
from injector import Binder, Injector, Module, inject, multiprovider, singleton
from prometheus_client.metrics import Counter, Gauge
from werkzeug import Request
from werkzeug.exceptions import HTTPException, InternalServerError
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from werkzeug.routing import Map, Rule
from rep0st.framework.decorator import DecoratorProcessor
from rep0st.framework.execute import execute
from rep0st.framework.signal_handler import on_shutdown
    return function

  return decorator


@singleton
class EndpointProcessor(DecoratorProcessor):
  injector: Injector = None
  web_server: WebServer = None

  @inject
  def __init__(self, injector: Injector, web_server: WebServer) -> None:
    super().__init__()
    self.injector = injector
    self.web_server = web_server

  def _wrap_request_response(self, fun) -> Callable:

    def f(environ, start_response, **kwargs):
      request = Request(environ)
      response = fun(request, **kwargs)
      return response(environ, start_response)

    return f

  def process(self, bindings: List[Any]) -> None:
    for interface, ep, fun in self.methods_by_decorated_name(
        bindings, 'endpoint'):
      full_fun_name = f'{interface.__module__}.{interface.__name__}.{fun.__name__}'
      log.info(f'Discovered endpoints on {full_fun_name} with rules {ep.rules}')

# Path: rep0st/framework/decorator.py
# class DecoratorProcessor(ABC):
# 
#   @abstractmethod
#   def process(self, bindings: List[Any]) -> None:
#     pass
# 
#   def methods_by_decorated_name(
#       self, bindings: List[Any],
#       search_name: str) -> Iterator[Tuple[Type, T, Callable[[Any], Any]]]:
#     for binding in bindings:
#       interface = binding
#       for name, fun in inspect.getmembers(interface):
#         data = getattr(fun, '__' + search_name + '__', None)
#         if data is not None:
#           yield (interface, data, fun)
# 
#   @staticmethod
#   def wrap_function(instance: Any, fun: Callable,
#                     injector: Injector) -> Callable:
#     fun = types.MethodType(fun, instance)
# 
#     @functools.wraps(fun)
#     def wrapper(*args: Any, **kwargs: Any) -> Any:
#       return injector.call_with_injection(
#           callable=fun, args=args, kwargs=kwargs)
# 
#     return wrapper  # type: ignore
# 
# Path: rep0st/framework/execute.py
# def execute(order: float = 0) -> Any:
# 
#   def decorator(function: Any):
#     function.__execute__ = _ExecuteConfiguration(order)
#     return function
# 
#   return decorator
# 
# Path: rep0st/framework/signal_handler.py
# def on_shutdown() -> Any:
# 
#   def decorator(function: Any):
#     function.__on_shutdown__ = _OnShutdownConfiguration()
#     return function
# 
#   return decorator


# Path: rep0st/framework/web.py
import logging
import random
import threading
import time
from abc import ABC
from threading import Thread
from typing import Any, Callable, Collection, List, NamedTuple, NewType, Union
from absl import flags
from cheroot.wsgi import Server as WSGIServer
from injector import Binder, Injector, Module, inject, multiprovider, singleton
from prometheus_client.metrics import Counter, Gauge
from werkzeug import Request
from werkzeug.exceptions import HTTPException, InternalServerError
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from werkzeug.routing import Map, Rule
from rep0st.framework.decorator import DecoratorProcessor
from rep0st.framework.execute import execute
from rep0st.framework.signal_handler import on_shutdown

    return function

  return decorator


@singleton
class EndpointProcessor(DecoratorProcessor):
  injector: Injector = None
  web_server: WebServer = None

  @inject
  def __init__(self, injector: Injector, web_server: WebServer) -> None:
    super().__init__()
    self.injector = injector
    self.web_server = web_server

  def _wrap_request_response(self, fun) -> Callable:

    def f(environ, start_response, **kwargs):
      request = Request(environ)
      response = fun(request, **kwargs)
      return response(environ, start_response)

    return f

  def process(self, bindings: List[Any]) -> None:
    for interface, ep, fun in self.methods_by_decorated_name(
        bindings, 'endpoint'):
      full_fun_name = f'{interface.__module__}.{interface.__name__}.{fun.__name__}'
      log.info(f'Discovered endpoints on {full_fun_name} with rules {ep.rules}')

      wrapped_fun = DecoratorProcessor.wrap_function(