capnproto-java-rpc/runtime/src/main/java/org/capnproto/TwoPartyServer.java

146 lines
5.1 KiB
Java
Raw Normal View History

2020-09-29 13:08:23 +00:00
package org.capnproto;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
2020-10-20 20:42:20 +00:00
import java.util.concurrent.CompletionStage;
2020-09-29 13:08:23 +00:00
public class TwoPartyServer {
private class AcceptedConnection {
2020-10-20 20:42:20 +00:00
final AsynchronousSocketChannel channel;
2020-09-29 13:08:23 +00:00
final TwoPartyVatNetwork network;
final TwoPartyRpcSystem rpcSystem;
2020-10-20 20:42:20 +00:00
private final CompletableFuture<?> messageLoop;
2020-09-29 13:08:23 +00:00
2020-10-20 20:42:20 +00:00
AcceptedConnection(Capability.Client bootstrapInterface, AsynchronousSocketChannel channel) {
2020-09-29 13:08:23 +00:00
this.channel = channel;
this.network = new TwoPartyVatNetwork(channel, RpcTwoPartyProtocol.Side.SERVER);
this.rpcSystem = new TwoPartyRpcSystem(network, bootstrapInterface);
2020-10-20 20:42:20 +00:00
this.messageLoop = this.rpcSystem.getMessageLoop().exceptionally(exc -> {
connections.remove(this);
return null;
});
2020-09-29 13:08:23 +00:00
}
2020-10-20 20:42:20 +00:00
public CompletableFuture<?> getMessageLoop() {
return this.messageLoop;
}
}
class ConnectionReceiver {
AsynchronousServerSocketChannel listener;
final CompletableFuture<?> messageLoop;
public ConnectionReceiver(AsynchronousServerSocketChannel listener) {
this.listener = listener;
this.messageLoop = doMessageLoop();
}
public CompletableFuture<?> getMessageLoop() {
return this.messageLoop;
}
private CompletableFuture<?> doMessageLoop() {
final var accepted = new CompletableFuture<AsynchronousSocketChannel>();
listener.accept(null, new CompletionHandler<>() {
@Override
public void completed(AsynchronousSocketChannel channel, Object attachment) {
accepted.complete(channel);
}
@Override
public void failed(Throwable exc, Object attachment) {
accepted.completeExceptionally(exc);
}
});
return accepted.thenCompose(channel -> CompletableFuture.allOf(
accept(channel),
doMessageLoop()));
2020-09-29 13:08:23 +00:00
}
}
private final Capability.Client bootstrapInterface;
private final List<AcceptedConnection> connections = new ArrayList<>();
2020-10-20 20:42:20 +00:00
private final List<ConnectionReceiver> listeners = new ArrayList<>();
private final CompletableFuture<?> messageLoop;
2020-09-29 13:08:23 +00:00
public TwoPartyServer(Capability.Client bootstrapInterface) {
this.bootstrapInterface = bootstrapInterface;
2020-10-20 20:42:20 +00:00
this.messageLoop = doMessageLoop();
}
public TwoPartyServer(Capability.Server bootstrapServer) {
this(new Capability.Client(bootstrapServer));
}
private CompletableFuture<?> getMessageLoop() {
return this.messageLoop;
2020-09-29 13:08:23 +00:00
}
2020-10-20 20:42:20 +00:00
public CompletableFuture<?> drain() {
CompletableFuture<java.lang.Void> done = new CompletableFuture<>();
for (var conn: this.connections) {
done = CompletableFuture.allOf(done, conn.getMessageLoop());
}
return done;
}
private CompletableFuture<java.lang.Void> accept(AsynchronousSocketChannel channel) {
2020-09-29 13:08:23 +00:00
var connection = new AcceptedConnection(this.bootstrapInterface, channel);
this.connections.add(connection);
2020-10-20 20:42:20 +00:00
return connection.network.onDisconnect().whenComplete((x, exc) -> {
this.connections.remove(connection);
});
2020-09-29 13:08:23 +00:00
}
2020-10-20 20:42:20 +00:00
/*
private final CompletableFuture<?> acceptLoop(AsynchronousServerSocketChannel listener) {
final var accepted = new CompletableFuture<AsynchronousSocketChannel>();
listener.accept(null, new CompletionHandler<>() {
2020-09-29 13:08:23 +00:00
@Override
public void completed(AsynchronousSocketChannel channel, Object attachment) {
2020-10-20 20:42:20 +00:00
accepted.complete(channel);
2020-09-29 13:08:23 +00:00
}
@Override
public void failed(Throwable exc, Object attachment) {
2020-10-20 20:42:20 +00:00
accepted.completeExceptionally(exc);
2020-09-29 13:08:23 +00:00
}
});
2020-10-20 20:42:20 +00:00
return accepted.thenCompose(channel -> CompletableFuture.anyOf(
accept(channel),
acceptLoop(listener)));
}
*/
public CompletableFuture<?> listen(AsynchronousServerSocketChannel listener) {
var receiver = new ConnectionReceiver(listener);
this.listeners.add(receiver);
return receiver.getMessageLoop();
}
private CompletableFuture<?> doMessageLoop() {
var done = new CompletableFuture<>();
for (var conn: this.connections) {
done = CompletableFuture.anyOf(done, conn.getMessageLoop());
}
for (var listener: this.listeners) {
done = CompletableFuture.anyOf(done, listener.getMessageLoop());
}
return done.thenCompose(x -> doMessageLoop());
2020-09-29 13:08:23 +00:00
}
2020-10-20 20:42:20 +00:00
/*
public CompletableFuture<?> runOnce() {
2020-10-14 14:54:21 +00:00
var done = new CompletableFuture<>();
2020-09-29 13:08:23 +00:00
for (var conn: connections) {
done = CompletableFuture.anyOf(done, conn.runOnce());
}
return done;
}
2020-10-20 20:42:20 +00:00
*/
2020-09-29 13:08:23 +00:00
}