Move ClientGet implementation to its own class
[jFCPlib.git] / src / main / java / net / pterodactylus / fcp / quelaton / DefaultFcpClient.java
1 package net.pterodactylus.fcp.quelaton;
2
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;
9
10 import net.pterodactylus.fcp.ClientHello;
11 import net.pterodactylus.fcp.CloseConnectionDuplicateClientName;
12 import net.pterodactylus.fcp.FcpConnection;
13 import net.pterodactylus.fcp.NodeHello;
14
15 /**
16  * Default {@link FcpClient} implementation.
17  *
18  * @author <a href="bombe@freenetproject.org">David ‘Bombe’ Roden</a>
19  */
20 public class DefaultFcpClient implements FcpClient {
21
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;
28
29         public DefaultFcpClient(ExecutorService threadPool, String hostname, int port, Supplier<String> clientName,
30                         Supplier<String> expectedVersion) {
31                 this.threadPool = threadPool;
32                 this.hostname = hostname;
33                 this.port = port;
34                 this.clientName = clientName;
35                 this.expectedVersion = expectedVersion;
36         }
37
38         private FcpConnection connect() throws IOException {
39                 FcpConnection fcpConnection = this.fcpConnection.get();
40                 if (fcpConnection != null) {
41                         return fcpConnection;
42                 }
43                 fcpConnection = createConnection();
44                 this.fcpConnection.compareAndSet(null, fcpConnection);
45                 return fcpConnection;
46         }
47
48         private FcpConnection createConnection() throws IOException {
49                 FcpConnection connection = new FcpConnection(hostname, port);
50                 connection.connect();
51                 FcpReplySequence<?> nodeHelloSequence = new FcpReplySequence<Void>(threadPool, connection) {
52                         private final AtomicReference<NodeHello> receivedNodeHello = new AtomicReference<>();
53                         private final AtomicBoolean receivedClosed = new AtomicBoolean();
54                         @Override
55                         protected boolean isFinished() {
56                                 return receivedNodeHello.get() != null || receivedClosed.get();
57                         }
58
59                         @Override
60                         protected void consumeNodeHello(NodeHello nodeHello) {
61                                 receivedNodeHello.set(nodeHello);
62                         }
63
64                         @Override
65                         protected void consumeCloseConnectionDuplicateClientName(
66                                 CloseConnectionDuplicateClientName closeConnectionDuplicateClientName) {
67                                 receivedClosed.set(true);
68                         }
69                 };
70                 ClientHello clientHello = new ClientHello(clientName.get(), expectedVersion.get());
71                 try {
72                         nodeHelloSequence.send(clientHello).get();
73                 } catch (InterruptedException | ExecutionException e) {
74                         connection.close();
75                         throw new IOException(String.format("Could not connect to %s:%d.", hostname, port), e);
76                 }
77                 return connection;
78         }
79
80         @Override
81         public GenerateKeypairCommand generateKeypair() {
82                 return new GenerateKeypairCommandImpl(threadPool, this::connect);
83         }
84
85         @Override
86         public ClientGetCommand clientGet() {
87                 return new ClientGetCommandImpl(threadPool, this::connect);
88         }
89
90 }
91