1 package net.pterodactylus.fcp.quelaton;
3 import java.io.IOException;
4 import java.util.concurrent.ExecutionException;
5 import java.util.concurrent.ExecutorService;
6 import java.util.concurrent.atomic.AtomicBoolean;
7 import java.util.concurrent.atomic.AtomicReference;
8 import java.util.function.Supplier;
10 import net.pterodactylus.fcp.ClientHello;
11 import net.pterodactylus.fcp.CloseConnectionDuplicateClientName;
12 import net.pterodactylus.fcp.FcpConnection;
13 import net.pterodactylus.fcp.NodeHello;
16 * Default {@link FcpClient} implementation.
18 * @author <a href="bombe@freenetproject.org">David ‘Bombe’ Roden</a>
20 public class DefaultFcpClient implements FcpClient {
22 private final ExecutorService threadPool;
23 private final String hostname;
24 private final int port;
25 private final AtomicReference<FcpConnection> fcpConnection = new AtomicReference<>();
26 private final Supplier<String> clientName;
27 private final Supplier<String> expectedVersion;
29 public DefaultFcpClient(ExecutorService threadPool, String hostname, int port, Supplier<String> clientName,
30 Supplier<String> expectedVersion) {
31 this.threadPool = threadPool;
32 this.hostname = hostname;
34 this.clientName = clientName;
35 this.expectedVersion = expectedVersion;
38 private FcpConnection connect() throws IOException {
39 FcpConnection fcpConnection = this.fcpConnection.get();
40 if (fcpConnection != null) {
43 fcpConnection = createConnection();
44 this.fcpConnection.compareAndSet(null, fcpConnection);
48 private FcpConnection createConnection() throws IOException {
49 FcpConnection connection = new FcpConnection(hostname, port);
51 FcpReplySequence<?> nodeHelloSequence = new FcpReplySequence<Void>(threadPool, connection) {
52 private final AtomicReference<NodeHello> receivedNodeHello = new AtomicReference<>();
53 private final AtomicBoolean receivedClosed = new AtomicBoolean();
55 protected boolean isFinished() {
56 return receivedNodeHello.get() != null || receivedClosed.get();
60 protected void consumeNodeHello(NodeHello nodeHello) {
61 receivedNodeHello.set(nodeHello);
65 protected void consumeCloseConnectionDuplicateClientName(
66 CloseConnectionDuplicateClientName closeConnectionDuplicateClientName) {
67 receivedClosed.set(true);
70 ClientHello clientHello = new ClientHello(clientName.get(), expectedVersion.get());
72 nodeHelloSequence.send(clientHello).get();
73 } catch (InterruptedException | ExecutionException e) {
75 throw new IOException(String.format("Could not connect to %s:%d.", hostname, port), e);
81 public GenerateKeypairCommand generateKeypair() {
82 return new GenerateKeypairCommandImpl(threadPool, this::connect);
86 public ClientGetCommand clientGet() {
87 return new ClientGetCommandImpl(threadPool, this::connect);