package io.muoncore.transport.client;
import io.muoncore.message.MuonMessage;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscription;
import reactor.Environment;
import reactor.core.Dispatcher;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.Predicate;
public class SimpleTransportMessageDispatcher implements TransportMessageDispatcher {
private List<QueuePredicate> queues = new ArrayList<>();
private ExecutorService exec = Executors.newFixedThreadPool(20);
private Dispatcher dispatcher = Environment.newDispatcher();
private static final MuonMessage POISON = new MuonMessage(null, 0, null, null, null, null, null,null,null, null);
@Override
public void dispatch(MuonMessage message) {
dispatcher.dispatch(message, m ->
queues.stream().forEach(msg -> msg.add(m)), Throwable::printStackTrace);
}
@Override
public void shutdown() {
dispatch(POISON);
exec.shutdown();
}
@Override
public Publisher<MuonMessage> observe(Predicate<MuonMessage> filter) {
LinkedBlockingQueue<MuonMessage> queue = new LinkedBlockingQueue<>();
QueuePredicate wrapper = new QueuePredicate(queue, filter);
queues.add(wrapper);
return s -> s.onSubscribe(new Subscription() {
@Override
public void request(long n) {
exec.execute(() -> {
for (int i = 0; i < n; i++) {
try {
MuonMessage msg = queue.take();
if (msg == POISON) {
s.onComplete();
return;
} else {
s.onNext(msg);
}
} catch (InterruptedException e) {
s.onError(e);
}
}
});
}
@Override
public void cancel() {
queues.remove(wrapper);
queue.clear();
}
});
}
static class QueuePredicate {
private Queue<MuonMessage> queue;
private Predicate<MuonMessage> predicate;
public QueuePredicate(Queue<MuonMessage> queue, Predicate<MuonMessage> predicate) {
this.queue = queue;
this.predicate = predicate;
}
public void add(MuonMessage msg) {
if (msg == null) return;
if (predicate.test(msg)) {
queue.add(msg);
}
}
}
}