From 23a08a2bd81e2742deb59fca70f6fe7d3a517cfc Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Mon, 13 Jul 2015 07:16:15 +0200 Subject: [PATCH] Add ListPeerNotes command --- .../fcp/quelaton/DefaultFcpClient.java | 5 + .../net/pterodactylus/fcp/quelaton/FcpClient.java | 1 + .../fcp/quelaton/ListPeerNotesCommand.java | 19 ++++ .../fcp/quelaton/ListPeerNotesCommandImpl.java | 101 +++++++++++++++++++ .../fcp/quelaton/DefaultFcpClientTest.java | 109 +++++++++++++++++++++ 5 files changed, 235 insertions(+) create mode 100644 src/main/java/net/pterodactylus/fcp/quelaton/ListPeerNotesCommand.java create mode 100644 src/main/java/net/pterodactylus/fcp/quelaton/ListPeerNotesCommandImpl.java diff --git a/src/main/java/net/pterodactylus/fcp/quelaton/DefaultFcpClient.java b/src/main/java/net/pterodactylus/fcp/quelaton/DefaultFcpClient.java index 574afc6..09b154b 100644 --- a/src/main/java/net/pterodactylus/fcp/quelaton/DefaultFcpClient.java +++ b/src/main/java/net/pterodactylus/fcp/quelaton/DefaultFcpClient.java @@ -84,5 +84,10 @@ public class DefaultFcpClient implements FcpClient { return new AddPeerCommandImpl(threadPool, this::connect); } + @Override + public ListPeerNotesCommand listPeerNotes() { + return new ListPeerNotesCommandImpl(threadPool, this::connect); + } + } diff --git a/src/main/java/net/pterodactylus/fcp/quelaton/FcpClient.java b/src/main/java/net/pterodactylus/fcp/quelaton/FcpClient.java index 5b61979..6864e5d 100644 --- a/src/main/java/net/pterodactylus/fcp/quelaton/FcpClient.java +++ b/src/main/java/net/pterodactylus/fcp/quelaton/FcpClient.java @@ -15,5 +15,6 @@ public interface FcpClient { ListPeerCommand listPeer(); ListPeersCommand listPeers(); AddPeerCommand addPeer(); + ListPeerNotesCommand listPeerNotes(); } diff --git a/src/main/java/net/pterodactylus/fcp/quelaton/ListPeerNotesCommand.java b/src/main/java/net/pterodactylus/fcp/quelaton/ListPeerNotesCommand.java new file mode 100644 index 0000000..ebe4a4d --- /dev/null +++ b/src/main/java/net/pterodactylus/fcp/quelaton/ListPeerNotesCommand.java @@ -0,0 +1,19 @@ +package net.pterodactylus.fcp.quelaton; + +import java.util.Optional; + +import net.pterodactylus.fcp.PeerNote; + +/** + * List the peer notes of a single peer by its name (darknet only), node identifier, or host name/IP address and port + * number. + * + * @author David ‘Bombe’ Roden + */ +public interface ListPeerNotesCommand { + + Executable> byName(String name); + Executable> byIdentity(String identity); + Executable> byHostAndPort(String host, int port); + +} diff --git a/src/main/java/net/pterodactylus/fcp/quelaton/ListPeerNotesCommandImpl.java b/src/main/java/net/pterodactylus/fcp/quelaton/ListPeerNotesCommandImpl.java new file mode 100644 index 0000000..426917a --- /dev/null +++ b/src/main/java/net/pterodactylus/fcp/quelaton/ListPeerNotesCommandImpl.java @@ -0,0 +1,101 @@ +package net.pterodactylus.fcp.quelaton; + +import java.io.IOException; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import net.pterodactylus.fcp.EndListPeerNotes; +import net.pterodactylus.fcp.ListPeerNotes; +import net.pterodactylus.fcp.PeerNote; +import net.pterodactylus.fcp.UnknownNodeIdentifier; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +/** + * Default {@link ListPeerNotesCommand} implementation based on {@link FcpDialog}. + * + * @author David ‘Bombe’ Roden + */ +public class ListPeerNotesCommandImpl implements ListPeerNotesCommand { + + private final ListeningExecutorService threadPool; + private final ConnectionSupplier connectionSupplier; + private final AtomicReference nodeIdentifier = new AtomicReference<>(); + + public ListPeerNotesCommandImpl(ExecutorService threadPool, ConnectionSupplier connectionSupplier) { + this.threadPool = MoreExecutors.listeningDecorator(threadPool); + this.connectionSupplier = connectionSupplier; + } + + @Override + public Executable> byName(String name) { + nodeIdentifier.set(name); + return this::execute; + } + + @Override + public Executable> byIdentity(String identity) { + nodeIdentifier.set(identity); + return this::execute; + } + + @Override + public Executable> byHostAndPort(String host, int port) { + nodeIdentifier.set(String.format("%s:%d", host, port)); + return this::execute; + } + + private ListenableFuture> execute() { + return threadPool.submit(this::executeSequence); + } + + private Optional executeSequence() throws IOException, ExecutionException, InterruptedException { + ListPeerNotes listPeerNotes = + new ListPeerNotes(new RandomIdentifierGenerator().generate(), nodeIdentifier.get()); + try (ListPeerNotesDialog listPeerNotesDialog = new ListPeerNotesDialog()) { + return listPeerNotesDialog.send(listPeerNotes).get(); + } + } + + private class ListPeerNotesDialog extends FcpDialog> { + + private final AtomicReference peerNote = new AtomicReference<>(); + private final AtomicBoolean finished = new AtomicBoolean(); + + public ListPeerNotesDialog() throws IOException { + super(threadPool, connectionSupplier.get()); + } + + @Override + protected boolean isFinished() { + return finished.get(); + } + + @Override + protected Optional getResult() { + return Optional.ofNullable(peerNote.get()); + } + + @Override + protected void consumePeerNote(PeerNote peerNote) { + this.peerNote.set(peerNote); + } + + @Override + protected void consumeEndListPeerNotes(EndListPeerNotes endListPeerNotes) { + finished.set(true); + } + + @Override + protected void consumeUnknownNodeIdentifier(UnknownNodeIdentifier unknownNodeIdentifier) { + finished.set(true); + } + + } + +} diff --git a/src/test/java/net/pterodactylus/fcp/quelaton/DefaultFcpClientTest.java b/src/test/java/net/pterodactylus/fcp/quelaton/DefaultFcpClientTest.java index a8dda59..ed89328 100644 --- a/src/test/java/net/pterodactylus/fcp/quelaton/DefaultFcpClientTest.java +++ b/src/test/java/net/pterodactylus/fcp/quelaton/DefaultFcpClientTest.java @@ -29,6 +29,7 @@ import net.pterodactylus.fcp.Key; import net.pterodactylus.fcp.NodeData; import net.pterodactylus.fcp.NodeRef; import net.pterodactylus.fcp.Peer; +import net.pterodactylus.fcp.PeerNote; import net.pterodactylus.fcp.Priority; import net.pterodactylus.fcp.fake.FakeTcpServer; import net.pterodactylus.fcp.quelaton.ClientGetCommand.Data; @@ -1133,4 +1134,112 @@ public class DefaultFcpClientTest { assertThat(peer.get().get().getIdentity(), is("id1")); } + @Test + public void listPeerNotesCanGetPeerNotesByNodeName() throws InterruptedException, ExecutionException, IOException { + Future> peerNote = fcpClient.listPeerNotes().byName("Friend1").execute(); + connectNode(); + List lines = fcpServer.collectUntil(is("EndMessage")); + String identifier = extractIdentifier(lines); + assertThat(lines, matchesFcpMessage( + "ListPeerNotes", + "NodeIdentifier=Friend1", + "EndMessage" + )); + fcpServer.writeLine( + "PeerNote", + "Identifier=" + identifier, + "NodeIdentifier=Friend1", + "NoteText=RXhhbXBsZSBUZXh0Lg==", + "PeerNoteType=1", + "EndMessage" + ); + fcpServer.writeLine( + "EndListPeerNotes", + "Identifier=" + identifier, + "EndMessage" + ); + assertThat(peerNote.get().get().getNoteText(), is("RXhhbXBsZSBUZXh0Lg==")); + assertThat(peerNote.get().get().getPeerNoteType(), is(1)); + } + + @Test + public void listPeerNotesReturnsEmptyOptionalWhenNodeIdenfierUnknown() + throws InterruptedException, ExecutionException, + IOException { + Future> peerNote = fcpClient.listPeerNotes().byName("Friend1").execute(); + connectNode(); + List lines = fcpServer.collectUntil(is("EndMessage")); + String identifier = extractIdentifier(lines); + assertThat(lines, matchesFcpMessage( + "ListPeerNotes", + "NodeIdentifier=Friend1", + "EndMessage" + )); + fcpServer.writeLine( + "UnknownNodeIdentifier", + "Identifier=" + identifier, + "NodeIdentifier=Friend1", + "EndMessage" + ); + assertThat(peerNote.get().isPresent(), is(false)); + } + + @Test + public void listPeerNotesCanGetPeerNotesByNodeIdentifier() + throws InterruptedException, ExecutionException, IOException { + Future> peerNote = fcpClient.listPeerNotes().byIdentity("id1").execute(); + connectNode(); + List lines = fcpServer.collectUntil(is("EndMessage")); + String identifier = extractIdentifier(lines); + assertThat(lines, matchesFcpMessage( + "ListPeerNotes", + "NodeIdentifier=id1", + "EndMessage" + )); + fcpServer.writeLine( + "PeerNote", + "Identifier=" + identifier, + "NodeIdentifier=id1", + "NoteText=RXhhbXBsZSBUZXh0Lg==", + "PeerNoteType=1", + "EndMessage" + ); + fcpServer.writeLine( + "EndListPeerNotes", + "Identifier=" + identifier, + "EndMessage" + ); + assertThat(peerNote.get().get().getNoteText(), is("RXhhbXBsZSBUZXh0Lg==")); + assertThat(peerNote.get().get().getPeerNoteType(), is(1)); + } + + @Test + public void listPeerNotesCanGetPeerNotesByHostNameAndPortNumber() + throws InterruptedException, ExecutionException, IOException { + Future> peerNote = fcpClient.listPeerNotes().byHostAndPort("1.2.3.4", 5678).execute(); + connectNode(); + List lines = fcpServer.collectUntil(is("EndMessage")); + String identifier = extractIdentifier(lines); + assertThat(lines, matchesFcpMessage( + "ListPeerNotes", + "NodeIdentifier=1.2.3.4:5678", + "EndMessage" + )); + fcpServer.writeLine( + "PeerNote", + "Identifier=" + identifier, + "NodeIdentifier=id1", + "NoteText=RXhhbXBsZSBUZXh0Lg==", + "PeerNoteType=1", + "EndMessage" + ); + fcpServer.writeLine( + "EndListPeerNotes", + "Identifier=" + identifier, + "EndMessage" + ); + assertThat(peerNote.get().get().getNoteText(), is("RXhhbXBsZSBUZXh0Lg==")); + assertThat(peerNote.get().get().getPeerNoteType(), is(1)); + } + } -- 2.7.4