static Graph<FlowShape<WithSender, WithSender>, NotUsed> fromFunction(
@Nullable final ActorRef self,
final Function<WithDittoHeaders, CompletionStage<WithDittoHeaders>> processor) {
final Attributes logLevels =
Attributes.createLogLevels(Logging.DebugLevel(), Logging.DebugLevel(), Logging.ErrorLevel());
final Flow<WithSender<WithDittoHeaders>, WithSender, NotUsed> flow =
Flow.<WithSender<WithDittoHeaders>>create()
.mapAsync(1, wrapped -> {
final Supplier<CompletionStage<Object>> futureSupplier = () ->
processor.apply(wrapped.getMessage())
.<Object>thenApply(result -> WithSender.of(result, wrapped.getSender()));
return handleErrorNowOrLater(futureSupplier, wrapped, self);
})
.log("PreEnforcer")
.withAttributes(logLevels)
.flatMapConcat(PreEnforcer::keepResultAndLogErrors);
return Pipe.joinUnhandledSink(
Pipe.joinFilteredFlow(Filter.of(WithDittoHeaders.class), flow), unhandled());
}