From: David ‘Bombe’ Roden Date: Tue, 14 Jul 2015 18:50:32 +0000 (+0200) Subject: Add command that modifies the note of a peer X-Git-Url: https://git.pterodactylus.net/?a=commitdiff_plain;h=6d4316ea0944d8c38552983aac7855fa2e466129;p=jFCPlib.git Add command that modifies the note of a peer --- diff --git a/src/main/java/net/pterodactylus/fcp/quelaton/DefaultFcpClient.java b/src/main/java/net/pterodactylus/fcp/quelaton/DefaultFcpClient.java index 0d180cb..1fc03bb 100644 --- a/src/main/java/net/pterodactylus/fcp/quelaton/DefaultFcpClient.java +++ b/src/main/java/net/pterodactylus/fcp/quelaton/DefaultFcpClient.java @@ -101,5 +101,10 @@ public class DefaultFcpClient implements FcpClient { return new ListPeerNotesCommandImpl(threadPool, this::connect); } + @Override + public ModifyPeerNoteCommand modifyPeerNote() { + return new ModifyPeerNoteCommandImpl(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 c2333da..dbd35f2 100644 --- a/src/main/java/net/pterodactylus/fcp/quelaton/FcpClient.java +++ b/src/main/java/net/pterodactylus/fcp/quelaton/FcpClient.java @@ -19,5 +19,6 @@ public interface FcpClient { RemovePeerCommand removePeer(); ListPeerNotesCommand listPeerNotes(); + ModifyPeerNoteCommand modifyPeerNote(); } diff --git a/src/main/java/net/pterodactylus/fcp/quelaton/ModifyPeerNoteCommand.java b/src/main/java/net/pterodactylus/fcp/quelaton/ModifyPeerNoteCommand.java new file mode 100644 index 0000000..713c8eb --- /dev/null +++ b/src/main/java/net/pterodactylus/fcp/quelaton/ModifyPeerNoteCommand.java @@ -0,0 +1,14 @@ +package net.pterodactylus.fcp.quelaton; + +/** + * Command that modifies the note of a peer. + * + * @author David ‘Bombe’ Roden + */ +public interface ModifyPeerNoteCommand { + + ModifyPeerNoteCommand darknetComment(String text); + + Executable byName(String name); + +} diff --git a/src/main/java/net/pterodactylus/fcp/quelaton/ModifyPeerNoteCommandImpl.java b/src/main/java/net/pterodactylus/fcp/quelaton/ModifyPeerNoteCommandImpl.java new file mode 100644 index 0000000..6b2ff71 --- /dev/null +++ b/src/main/java/net/pterodactylus/fcp/quelaton/ModifyPeerNoteCommandImpl.java @@ -0,0 +1,101 @@ +package net.pterodactylus.fcp.quelaton; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +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.FreenetBase64; +import net.pterodactylus.fcp.ModifyPeerNote; +import net.pterodactylus.fcp.PeerNote; +import net.pterodactylus.fcp.PeerNoteType; +import net.pterodactylus.fcp.UnknownNodeIdentifier; + +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +/** + * Default {@link ModifyPeerNoteCommand} implementation based on {@link FcpDialog}. + * + * @author David ‘Bombe’ Roden + */ +public class ModifyPeerNoteCommandImpl implements ModifyPeerNoteCommand { + + private static final FreenetBase64 BASE_64 = new FreenetBase64(); + private static final RandomIdentifierGenerator RANDOM_IDENTIFIER_GENERATOR = new RandomIdentifierGenerator(); + private final ListeningExecutorService threadPool; + private final ConnectionSupplier connectionSupplier; + private final AtomicReference nodeIdentifier = new AtomicReference<>(); + private final AtomicReference darknetComment = new AtomicReference<>(); + + public ModifyPeerNoteCommandImpl(ExecutorService threadPool, ConnectionSupplier connectionSupplier) { + this.threadPool = MoreExecutors.listeningDecorator(threadPool); + this.connectionSupplier = connectionSupplier; + } + + @Override + public ModifyPeerNoteCommand darknetComment(String text) { + darknetComment.set(text); + return this; + } + + @Override + public Executable byName(String name) { + nodeIdentifier.set(name); + return this::execute; + } + + private ListenableFuture execute() { + if (darknetComment.get() == null) { + return Futures.immediateFuture(false); + } + return threadPool.submit(this::executeDialog); + } + + private Boolean executeDialog() throws IOException, ExecutionException, InterruptedException { + ModifyPeerNote modifyPeerNote = + new ModifyPeerNote(RANDOM_IDENTIFIER_GENERATOR.generate(), nodeIdentifier.get()); + modifyPeerNote.setPeerNoteType(PeerNoteType.PRIVATE_DARKNET_COMMENT); + modifyPeerNote.setNoteText(BASE_64.encode(darknetComment.get().getBytes(StandardCharsets.UTF_8))); + try (ModifyPeerNoteDialog modifyPeerNoteDialog = new ModifyPeerNoteDialog()) { + return modifyPeerNoteDialog.send(modifyPeerNote).get(); + } + } + + private class ModifyPeerNoteDialog extends FcpDialog { + + private final AtomicBoolean finished = new AtomicBoolean(); + private final AtomicBoolean successful = new AtomicBoolean(); + + public ModifyPeerNoteDialog() throws IOException { + super(threadPool, connectionSupplier.get()); + } + + @Override + protected boolean isFinished() { + return finished.get(); + } + + @Override + protected Boolean getResult() { + return successful.get(); + } + + @Override + protected void consumePeerNote(PeerNote peerNote) { + successful.set(true); + 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 2cfce98..e0b5a2e 100644 --- a/src/test/java/net/pterodactylus/fcp/quelaton/DefaultFcpClientTest.java +++ b/src/test/java/net/pterodactylus/fcp/quelaton/DefaultFcpClientTest.java @@ -1657,4 +1657,61 @@ public class DefaultFcpClientTest { assertThat(peer.get(), is(true)); } + @Test + public void defaultFcpClientCanModifyPeerNoteByName() + throws InterruptedException, ExecutionException, IOException { + Future noteUpdated = fcpClient.modifyPeerNote().darknetComment("foo").byName("Friend1").execute(); + connectNode(); + List lines = fcpServer.collectUntil(is("EndMessage")); + String identifier = extractIdentifier(lines); + assertThat(lines, matchesFcpMessage( + "ModifyPeerNote", + "Identifier=" + identifier, + "NodeIdentifier=Friend1", + "PeerNoteType=1", + "NoteText=Zm9v", + "EndMessage" + )); + fcpServer.writeLine( + "PeerNote", + "Identifier=" + identifier, + "NodeIdentifier=Friend1", + "NoteText=Zm9v", + "PeerNoteType=1", + "EndMessage" + ); + assertThat(noteUpdated.get(), is(true)); + } + + @Test + public void defaultFcpClientKnowsPeerNoteWasNotModifiedOnUnknownNodeIdentifier() + throws InterruptedException, ExecutionException, IOException { + Future noteUpdated = fcpClient.modifyPeerNote().darknetComment("foo").byName("Friend1").execute(); + connectNode(); + List lines = fcpServer.collectUntil(is("EndMessage")); + String identifier = extractIdentifier(lines); + assertThat(lines, matchesFcpMessage( + "ModifyPeerNote", + "Identifier=" + identifier, + "NodeIdentifier=Friend1", + "PeerNoteType=1", + "NoteText=Zm9v", + "EndMessage" + )); + fcpServer.writeLine( + "UnknownNodeIdentifier", + "Identifier=" + identifier, + "NodeIdentifier=Friend1", + "EndMessage" + ); + assertThat(noteUpdated.get(), is(false)); + } + + @Test + public void defaultFcpClientFailsToModifyPeerNoteWithoutPeerNote() + throws InterruptedException, ExecutionException, IOException { + Future noteUpdated = fcpClient.modifyPeerNote().byName("Friend1").execute(); + assertThat(noteUpdated.get(), is(false)); + } + }