================ Extending Koukan ================ router yaml:: modules: sync_filter: my_filter: path.to.my.filter recipient_router_policy: my_policy: path.to.my.policy:my_policy_factory will do something like:: from path.to.my.filter import factory filter = factory(filter_yaml) from path.to.my.policy import my_policy_factory policy = my_policy_factory(policy_yaml) Filters ======= Filter: returns FilterResult with a delta to be unconditionally merged into the upstream result. This enables a sort-of tail-call optimization; the filter is not invoked in the return path. ProxyFilter: whereas a regular Filter only conservatively extends the transaction, ProxyFilter has separate upstream and downstream transaction objects that it can implement an arbitrary transformation between. e.g. any filter that replaces/modifies tx.body (message builder, message parser, received header) must be ProxyFilter. CoroutineFilter: whereas regular Filter is not invoked in the return path, CoroutineFilters take a Callable to "yield to the scheduler" to continue the upstream chain which in turn yields a continuation to invoke in the return path. This allows arbitrary code in the return path. Historical note: we started with CoroutineFilter, then discovered the tail-call optimization was possible for filters in a "normal form" and then discovered that all of the filters fit into that. So we don't actually have a use case for this currently. CoroutineProxyFilter: ProxyFilter + CoroutineFilter Example: `hello_filter.py `__ RecipientRouterFilter Policies ============================== Implement ``recipient_router_filter.RoutingPolicy`` ``RoutingPolicy.endpoint_for_rcpt()`` is passed an element from ``TransactionMetadata.rcpt_to`` and returns either a ``Destination`` which controls where RestEndpoint sends it or a Response which is returned downstream in ``TransactionMetadata.rcpt_response`` if the address does not exist. Example: `hello_policy.py `__