2 * fcplib - HighLevelClient.java -
3 * Copyright © 2008 David Roden
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 package net.pterodactylus.fcp.highlevel;
22 import java.io.BufferedReader;
24 import java.io.FileReader;
25 import java.io.FileWriter;
26 import java.io.IOException;
27 import java.net.InetAddress;
29 import java.net.UnknownHostException;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.List;
35 import java.util.Map.Entry;
36 import java.util.logging.Level;
37 import java.util.logging.Logger;
39 import net.pterodactylus.fcp.AddPeer;
40 import net.pterodactylus.fcp.AllData;
41 import net.pterodactylus.fcp.ClientGet;
42 import net.pterodactylus.fcp.ClientHello;
43 import net.pterodactylus.fcp.CloseConnectionDuplicateClientName;
44 import net.pterodactylus.fcp.ConfigData;
45 import net.pterodactylus.fcp.DataFound;
46 import net.pterodactylus.fcp.EndListPeerNotes;
47 import net.pterodactylus.fcp.EndListPeers;
48 import net.pterodactylus.fcp.EndListPersistentRequests;
49 import net.pterodactylus.fcp.FCPPluginReply;
50 import net.pterodactylus.fcp.FcpConnection;
51 import net.pterodactylus.fcp.FcpListener;
52 import net.pterodactylus.fcp.FcpMessage;
53 import net.pterodactylus.fcp.FcpUtils;
54 import net.pterodactylus.fcp.FinishedCompression;
55 import net.pterodactylus.fcp.GenerateSSK;
56 import net.pterodactylus.fcp.GetFailed;
57 import net.pterodactylus.fcp.IdentifierCollision;
58 import net.pterodactylus.fcp.ListPeers;
59 import net.pterodactylus.fcp.ListPersistentRequests;
60 import net.pterodactylus.fcp.NodeData;
61 import net.pterodactylus.fcp.NodeHello;
62 import net.pterodactylus.fcp.NodeRef;
63 import net.pterodactylus.fcp.Peer;
64 import net.pterodactylus.fcp.PeerNote;
65 import net.pterodactylus.fcp.PeerRemoved;
66 import net.pterodactylus.fcp.PersistentGet;
67 import net.pterodactylus.fcp.PersistentPut;
68 import net.pterodactylus.fcp.PersistentPutDir;
69 import net.pterodactylus.fcp.PersistentRequestModified;
70 import net.pterodactylus.fcp.PersistentRequestRemoved;
71 import net.pterodactylus.fcp.PluginInfo;
72 import net.pterodactylus.fcp.ProtocolError;
73 import net.pterodactylus.fcp.PutFailed;
74 import net.pterodactylus.fcp.PutFetchable;
75 import net.pterodactylus.fcp.PutSuccessful;
76 import net.pterodactylus.fcp.ReturnType;
77 import net.pterodactylus.fcp.SSKKeypair;
78 import net.pterodactylus.fcp.SimpleProgress;
79 import net.pterodactylus.fcp.StartedCompression;
80 import net.pterodactylus.fcp.SubscribedUSKUpdate;
81 import net.pterodactylus.fcp.TestDDAComplete;
82 import net.pterodactylus.fcp.TestDDAReply;
83 import net.pterodactylus.fcp.TestDDARequest;
84 import net.pterodactylus.fcp.TestDDAResponse;
85 import net.pterodactylus.fcp.URIGenerated;
86 import net.pterodactylus.fcp.UnknownNodeIdentifier;
87 import net.pterodactylus.fcp.UnknownPeerNoteType;
90 * A high-level client that allows simple yet full-featured access to a Freenet
93 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
96 public class HighLevelClient {
99 private static final Logger logger = Logger.getLogger(HighLevelClient.class.getName());
101 /** Object for internal synchronization. */
102 private final Object syncObject = new Object();
104 /** The name of the client. */
105 private final String clientName;
107 /** The address of the node. */
108 private InetAddress address;
110 /** The port number of the node. */
113 /** The FCP connection to the node. */
114 private FcpConnection fcpConnection;
116 /** Listeners for high-level client events. */
117 private List<HighLevelClientListener> highLevelClientListeners = Collections.synchronizedList(new ArrayList<HighLevelClientListener>());
119 /** The listener for the connection. */
120 private HighLevelClientFcpListener highLevelClientFcpListener = new HighLevelClientFcpListener();
122 /** The callback for {@link #connect()}. */
123 private HighLevelCallback<ConnectResult> connectCallback;
125 /** Mapping from request identifiers to callbacks. */
126 private Map<String, HighLevelCallback<KeyGenerationResult>> keyGenerationCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<KeyGenerationResult>>());
128 /** Mapping from request identifier to peer list callbacks. */
129 private Map<String, HighLevelCallback<PeerListResult>> peerListCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<PeerListResult>>());
131 /** Mapping from request identifier to peer callbacks. */
132 private Map<String, HighLevelCallback<PeerResult>> peerCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<PeerResult>>());
134 /** Mapping from directories to DDA callbacks. */
135 private Map<String, HighLevelCallback<DirectDiskAccessResult>> directDiskAccessCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<DirectDiskAccessResult>>());
137 /** Mapping from request identifiers to download callbacks. */
138 private Map<String, HighLevelProgressCallback<DownloadResult>> downloadCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelProgressCallback<DownloadResult>>());
140 /** The callback for {@link #getRequests()}. */
141 private HighLevelCallback<RequestListResult> requestListCallback;
144 * Creates a new high-level client that connects to a node on
145 * <code>localhost</code>.
148 * The name of the client
149 * @throws UnknownHostException
150 * if the hostname of the node can not be resolved.
152 public HighLevelClient(String clientName) throws UnknownHostException {
153 this(clientName, "localhost");
157 * Creates a new high-level client that connects to a node on the given
161 * The name of the client
163 * The hostname of the node
164 * @throws UnknownHostException
165 * if the hostname of the node can not be resolved.
167 public HighLevelClient(String clientName, String host) throws UnknownHostException {
168 this(clientName, host, FcpConnection.DEFAULT_PORT);
172 * Creates a new high-level client that connects to a node on the given
176 * The name of the client
178 * The hostname of the node
180 * The port number of the node
181 * @throws UnknownHostException
182 * if the hostname of the node can not be resolved.
184 public HighLevelClient(String clientName, String host, int port) throws UnknownHostException {
185 this(clientName, InetAddress.getByName(host), port);
189 * Creates a new high-level client that connects to a node at the given
193 * The name of the client
195 * The address of the node
197 * The port number of the node
199 public HighLevelClient(String clientName, InetAddress address, int port) {
200 this.clientName = clientName;
201 this.address = address;
210 * Adds the given high-level client listener to list of listeners.
212 * @param highLevelClientListener
213 * The listener to add
215 public void addHighLevelClientListener(HighLevelClientListener highLevelClientListener) {
216 highLevelClientListeners.add(highLevelClientListener);
220 * Removes the given high-level client listener from the list of listeners.
222 * @param highLevelClientListener
223 * The listener to remove
225 public void removeHighLevelClientListener(HighLevelClientListener highLevelClientListener) {
226 highLevelClientListeners.remove(highLevelClientListener);
230 * Notifies all listeners that a client has connected.
232 private void fireClientConnected() {
233 for (HighLevelClientListener highLevelClientListener: highLevelClientListeners) {
234 highLevelClientListener.clientConnected(this);
239 * Notifies all listeners that a client has disconnected.
242 * The exception that caused the disconnect, or <code>null</code>
243 * if there was no exception
245 private void fireClientDisconnected(Throwable throwable) {
246 for (HighLevelClientListener highLevelClientListener: highLevelClientListeners) {
247 highLevelClientListener.clientDisconnected(this, throwable);
256 * Returns the FCP connection that backs this high-level client. This method
257 * should be used with care as fiddling around with the FCP connection can
258 * easily break the high-level client if you don’t know what you’re doing!
260 * @return The FCP connection of this client
262 public FcpConnection getFcpConnection() {
263 return fcpConnection;
271 * Connects the client.
273 * @return A callback with a connection result
274 * @throws IOException
275 * if an I/O error occurs communicating with the node
277 public HighLevelCallback<ConnectResult> connect() throws IOException {
278 fcpConnection = new FcpConnection(address, port);
279 fcpConnection.addFcpListener(highLevelClientFcpListener);
280 fcpConnection.connect();
281 ClientHello clientHello = new ClientHello(clientName);
282 connectCallback = new HighLevelCallback<ConnectResult>(new ConnectResult());
283 fcpConnection.sendMessage(clientHello);
284 return connectCallback;
288 * Disconnects the client from the node.
290 public void disconnect() {
295 * Generates a new SSK keypair.
297 * @return A callback with the keypair
298 * @throws IOException
299 * if an I/O error occurs communicating with the node
301 public HighLevelCallback<KeyGenerationResult> generateKey() throws IOException {
302 String identifier = generateIdentifier("generateSSK");
303 GenerateSSK generateSSK = new GenerateSSK(identifier);
304 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = new HighLevelCallback<KeyGenerationResult>(new KeyGenerationResult(identifier));
305 keyGenerationCallbacks.put(identifier, keyGenerationCallback);
306 fcpConnection.sendMessage(generateSSK);
307 return keyGenerationCallback;
311 * Gets a list of all peers from the node.
313 * @return A callback with the peer list
314 * @throws IOException
315 * if an I/O error occurs with the node
317 public HighLevelCallback<PeerListResult> getPeers() throws IOException {
318 String identifier = generateIdentifier("listPeers");
319 ListPeers listPeers = new ListPeers(identifier, true, true);
320 HighLevelCallback<PeerListResult> peerListCallback = new HighLevelCallback<PeerListResult>(new PeerListResult(identifier));
321 peerListCallbacks.put(identifier, peerListCallback);
322 fcpConnection.sendMessage(listPeers);
323 return peerListCallback;
327 * Adds the peer whose noderef is stored in the given file.
330 * The name of the file the peer’s noderef is stored in
331 * @return A peer callback
332 * @throws IOException
333 * if an I/O error occurs communicating with the node
335 public HighLevelCallback<PeerResult> addPeer(String nodeRefFile) throws IOException {
336 String identifier = generateIdentifier("addPeer");
337 AddPeer addPeer = new AddPeer(nodeRefFile);
338 HighLevelCallback<PeerResult> peerCallback = new HighLevelCallback<PeerResult>(new PeerResult(identifier));
339 peerCallbacks.put(identifier, peerCallback);
340 fcpConnection.sendMessage(addPeer);
345 * Adds the peer whose noderef is stored in the given file.
348 * The URL where the peer’s noderef is stored
349 * @return A peer callback
350 * @throws IOException
351 * if an I/O error occurs communicating with the node
353 public HighLevelCallback<PeerResult> addPeer(URL nodeRefURL) throws IOException {
354 String identifier = generateIdentifier("addPeer");
355 AddPeer addPeer = new AddPeer(nodeRefURL);
356 HighLevelCallback<PeerResult> peerCallback = new HighLevelCallback<PeerResult>(new PeerResult(identifier));
357 peerCallbacks.put(identifier, peerCallback);
358 fcpConnection.sendMessage(addPeer);
363 * Adds the peer whose noderef is stored in the given file.
367 * @return A peer callback
368 * @throws IOException
369 * if an I/O error occurs communicating with the node
371 public HighLevelCallback<PeerResult> addPeer(NodeRef nodeRef) throws IOException {
372 String identifier = generateIdentifier("addPeer");
373 AddPeer addPeer = new AddPeer(nodeRef);
374 HighLevelCallback<PeerResult> peerCallback = new HighLevelCallback<PeerResult>(new PeerResult(identifier));
375 peerCallbacks.put(identifier, peerCallback);
376 fcpConnection.sendMessage(addPeer);
381 * Checks whether direct disk access for the given directory is possible.
382 * You have to perform this check before you can upload or download anything
383 * from or the disk directly!
386 * The directory to check
388 * Whether you want to read the given directory
390 * Whether you want to write to the given directory
391 * @return A direct disk access callback
392 * @throws IOException
394 public HighLevelCallback<DirectDiskAccessResult> checkDirectDiskAccess(String directory, boolean wantRead, boolean wantWrite) throws IOException {
395 TestDDARequest testDDARequest = new TestDDARequest(directory, wantRead, wantWrite);
396 HighLevelCallback<DirectDiskAccessResult> directDiskAccessCallback = new HighLevelCallback<DirectDiskAccessResult>(new DirectDiskAccessResult(directory));
397 directDiskAccessCallbacks.put(directory, directDiskAccessCallback);
398 fcpConnection.sendMessage(testDDARequest);
399 return directDiskAccessCallback;
403 * Starts a download. Files can either be download to disk or streamed from
404 * the node. When downloading to disk you have to perform a direct disk
405 * access check for the directory you want to put the downloaded file in!
407 * @see #checkDirectDiskAccess(String, boolean, boolean)
411 * The filename to save the data to, or <code>null</code> to
412 * retrieve the data as InputStream from the
413 * {@link DownloadResult}
415 * Whether to put the download on the global queue
416 * @return A download result
417 * @throws IOException
418 * if an I/O error occurs communicating with the node
420 public HighLevelProgressCallback<DownloadResult> download(String uri, String filename, boolean global) throws IOException {
421 String identifier = generateIdentifier("download");
422 ClientGet clientGet = new ClientGet(uri, identifier, (filename == null) ? ReturnType.direct : ReturnType.disk);
423 clientGet.setGlobal(global);
424 HighLevelProgressCallback<DownloadResult> downloadCallback = new HighLevelProgressCallback<DownloadResult>(new DownloadResult(identifier));
425 downloadCallbacks.put(identifier, downloadCallback);
426 fcpConnection.sendMessage(clientGet);
427 return downloadCallback;
431 * Requests a list of all running requests from the node.
433 * @return The request list result
434 * @throws IOException
435 * if an I/O errors communicating with the node
437 public HighLevelCallback<RequestListResult> getRequests() throws IOException {
438 String identifier = generateIdentifier("list-persistent-requests");
439 ListPersistentRequests listPersistentRequests = new ListPersistentRequests();
440 synchronized (syncObject) {
441 if (requestListCallback != null) {
442 logger.log(Level.SEVERE, "getRequests() called with request still running!");
444 requestListCallback = new HighLevelCallback<RequestListResult>(new RequestListResult(identifier));
446 fcpConnection.sendMessage(listPersistentRequests);
447 return requestListCallback;
455 * Generates an identifier for the given function.
458 * The name of the function
459 * @return An identifier
461 private String generateIdentifier(String function) {
462 return "jFCPlib-" + function + "-" + System.currentTimeMillis();
466 * Disconnects the client from the node, handing the given Throwable to
467 * {@link #fireClientDisconnected(Throwable)}.
470 * The exception that caused the disconnect, or <code>null</code>
471 * if there was no exception
473 private void disconnect(Throwable throwable) {
474 fcpConnection.close();
475 fireClientDisconnected(throwable);
479 * FCP listener for {@link HighLevelClient}.
481 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
484 private class HighLevelClientFcpListener implements FcpListener {
486 /** Mapping from directory to written file (for cleanup). */
487 private final Map<DirectDiskAccessResult, String> writtenFiles = new HashMap<DirectDiskAccessResult, String>();
490 * Creates a new FCP listener for {@link HighLevelClient}.
492 HighLevelClientFcpListener() {
501 * Searches all callback collections for a callback with the given
502 * identifier and cancels it.
505 * The identifier to search for, or <code>null</code> to
506 * cancel all pending requests
508 @SuppressWarnings("synthetic-access")
509 private void cancelIdentifier(String identifier) {
510 synchronized (syncObject) {
511 if (connectCallback != null) {
512 connectCallback.getIntermediaryResult().setFailed(true);
513 connectCallback.setDone();
514 connectCallback = null;
516 if (requestListCallback != null) {
517 requestListCallback.getIntermediaryResult().setFailed(true);
518 requestListCallback.setDone();
519 requestListCallback = null;
522 if (identifier == null) {
523 /* key generation callbacks */
524 for (Entry<String, HighLevelCallback<KeyGenerationResult>> keyGenerationEntry: keyGenerationCallbacks.entrySet()) {
525 keyGenerationEntry.getValue().getIntermediaryResult().setFailed(true);
526 keyGenerationEntry.getValue().setDone();
528 keyGenerationCallbacks.clear();
529 /* peer list callbacks. */
530 for (Entry<String, HighLevelCallback<PeerListResult>> peerListEntry: peerListCallbacks.entrySet()) {
531 peerListEntry.getValue().getIntermediaryResult().setFailed(true);
532 peerListEntry.getValue().setDone();
534 peerListCallbacks.clear();
535 /* peer callbacks. */
536 for (Entry<String, HighLevelCallback<PeerResult>> peerEntry: peerCallbacks.entrySet()) {
537 peerEntry.getValue().getIntermediaryResult().setFailed(true);
538 peerEntry.getValue().setDone();
540 peerCallbacks.clear();
541 /* direct disk access callbacks. */
542 for (Entry<String, HighLevelCallback<DirectDiskAccessResult>> directDiskAccessEntry: directDiskAccessCallbacks.entrySet()) {
543 directDiskAccessEntry.getValue().getIntermediaryResult().setFailed(true);
544 directDiskAccessEntry.getValue().setDone();
546 directDiskAccessCallbacks.clear();
547 /* download callbacks. */
548 for (Entry<String, HighLevelProgressCallback<DownloadResult>> downloadEntry: downloadCallbacks.entrySet()) {
549 downloadEntry.getValue().getIntermediaryResult().setFailed(true);
550 downloadEntry.getValue().setDone();
552 downloadCallbacks.clear();
554 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(identifier);
555 if (keyGenerationCallback != null) {
556 keyGenerationCallback.getIntermediaryResult().setFailed(true);
557 keyGenerationCallback.setDone();
560 HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.remove(identifier);
561 if (peerListCallback != null) {
562 peerListCallback.getIntermediaryResult().setFailed(true);
563 peerListCallback.setDone();
566 HighLevelCallback<PeerResult> peerCallback = peerCallbacks.remove(identifier);
567 if (peerCallback != null) {
568 peerCallback.getIntermediaryResult().setFailed(true);
569 peerCallback.setDone();
572 HighLevelCallback<DirectDiskAccessResult> directDiskAccessCallback = directDiskAccessCallbacks.remove(identifier);
573 if (directDiskAccessCallback != null) {
574 directDiskAccessCallback.getIntermediaryResult().setFailed(true);
575 directDiskAccessCallback.setDone();
578 HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.remove(identifier);
579 if (downloadCallback != null) {
580 downloadCallback.getIntermediaryResult().setFailed(true);
581 downloadCallback.setDone();
588 * Reads the given file and returns the first line of the file.
590 * @param readFilename
591 * The name of the file to read
592 * @return The content of the file
594 private String readContent(String readFilename) {
595 FileReader fileReader = null;
596 BufferedReader bufferedFileReader = null;
598 fileReader = new FileReader(readFilename);
599 bufferedFileReader = new BufferedReader(fileReader);
600 String content = bufferedFileReader.readLine();
602 } catch (IOException ioe1) {
605 FcpUtils.close(bufferedFileReader);
606 FcpUtils.close(fileReader);
612 * Writes the given content to the given file.
614 * @param directDiskAccessResult
616 * @param writeFilename
617 * The name of the file to write to
618 * @param writeContent
619 * The content to write to the file
621 private void writeContent(DirectDiskAccessResult directDiskAccessResult, String writeFilename, String writeContent) {
622 if ((writeFilename == null) || (writeContent == null)) {
625 writtenFiles.put(directDiskAccessResult, writeFilename);
626 FileWriter fileWriter = null;
628 fileWriter = new FileWriter(writeFilename);
629 fileWriter.write(writeContent);
630 } catch (IOException ioe1) {
633 FcpUtils.close(fileWriter);
638 * Cleans up any files that written for the given result.
640 * @param directDiskAccessResult
641 * The direct disk access result
643 @SuppressWarnings("synthetic-access")
644 private void cleanFiles(DirectDiskAccessResult directDiskAccessResult) {
645 String writeFilename = writtenFiles.remove(directDiskAccessResult);
646 if (writeFilename != null) {
647 if (!new File(writeFilename).delete()) {
648 logger.warning("could not delete " + writeFilename);
654 // INTERFACE FcpListener
658 * @see net.pterodactylus.fcp.FcpListener#connectionClosed(net.pterodactylus.fcp.FcpConnection,
661 @SuppressWarnings("synthetic-access")
662 public void connectionClosed(FcpConnection fcpConnection, Throwable throwable) {
663 if (fcpConnection != HighLevelClient.this.fcpConnection) {
666 cancelIdentifier(null);
667 disconnect(throwable);
671 * @see net.pterodactylus.fcp.FcpListener#receivedAllData(net.pterodactylus.fcp.FcpConnection,
672 * net.pterodactylus.fcp.AllData)
674 public void receivedAllData(FcpConnection fcpConnection, AllData allData) {
679 * @see net.pterodactylus.fcp.FcpListener#receivedCloseConnectionDuplicateClientName(net.pterodactylus.fcp.FcpConnection,
680 * net.pterodactylus.fcp.CloseConnectionDuplicateClientName)
682 public void receivedCloseConnectionDuplicateClientName(FcpConnection fcpConnection, CloseConnectionDuplicateClientName closeConnectionDuplicateClientName) {
687 * @see net.pterodactylus.fcp.FcpListener#receivedConfigData(net.pterodactylus.fcp.FcpConnection,
688 * net.pterodactylus.fcp.ConfigData)
690 public void receivedConfigData(FcpConnection fcpConnection, ConfigData configData) {
695 * @see net.pterodactylus.fcp.FcpListener#receivedDataFound(net.pterodactylus.fcp.FcpConnection,
696 * net.pterodactylus.fcp.DataFound)
698 public void receivedDataFound(FcpConnection fcpConnection, DataFound dataFound) {
703 * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeerNotes(net.pterodactylus.fcp.FcpConnection,
704 * net.pterodactylus.fcp.EndListPeerNotes)
706 public void receivedEndListPeerNotes(FcpConnection fcpConnection, EndListPeerNotes endListPeerNotes) {
711 * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeers(net.pterodactylus.fcp.FcpConnection,
712 * net.pterodactylus.fcp.EndListPeers)
714 @SuppressWarnings("synthetic-access")
715 public void receivedEndListPeers(FcpConnection fcpConnection, EndListPeers endListPeers) {
716 if (fcpConnection != HighLevelClient.this.fcpConnection) {
719 String identifier = endListPeers.getIdentifier();
720 HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.remove(identifier);
721 if (peerListCallback == null) {
724 peerListCallback.setDone();
728 * @see net.pterodactylus.fcp.FcpListener#receivedEndListPersistentRequests(net.pterodactylus.fcp.FcpConnection,
729 * net.pterodactylus.fcp.EndListPersistentRequests)
731 @SuppressWarnings("synthetic-access")
732 public void receivedEndListPersistentRequests(FcpConnection fcpConnection, EndListPersistentRequests endListPersistentRequests) {
733 if (fcpConnection != HighLevelClient.this.fcpConnection) {
736 synchronized (syncObject) {
737 if (HighLevelClient.this.requestListCallback == null) {
738 logger.log(Level.WARNING, "got EndListPersistentRequests without running request!");
741 requestListCallback.setDone();
742 requestListCallback = null;
747 * @see net.pterodactylus.fcp.FcpListener#receivedFCPPluginReply(net.pterodactylus.fcp.FcpConnection,
748 * net.pterodactylus.fcp.FCPPluginReply)
750 public void receivedFCPPluginReply(FcpConnection fcpConnection, FCPPluginReply fcpPluginReply) {
755 * @see net.pterodactylus.fcp.FcpListener#receivedGetFailed(net.pterodactylus.fcp.FcpConnection,
756 * net.pterodactylus.fcp.GetFailed)
758 @SuppressWarnings("synthetic-access")
759 public void receivedGetFailed(FcpConnection fcpConnection, GetFailed getFailed) {
760 if (fcpConnection != HighLevelClient.this.fcpConnection) {
763 String identifier = getFailed.getIdentifier();
764 HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.remove(identifier);
765 if (downloadCallback != null) {
766 downloadCallback.getIntermediaryResult().setFailed(true);
767 downloadCallback.setDone();
770 /* unknown identifier? */
771 logger.warning("unknown identifier for GetFailed: " + identifier);
775 * @see net.pterodactylus.fcp.FcpListener#receivedIdentifierCollision(net.pterodactylus.fcp.FcpConnection,
776 * net.pterodactylus.fcp.IdentifierCollision)
778 public void receivedIdentifierCollision(FcpConnection fcpConnection, IdentifierCollision identifierCollision) {
783 * @see net.pterodactylus.fcp.FcpListener#receivedMessage(net.pterodactylus.fcp.FcpConnection,
784 * net.pterodactylus.fcp.FcpMessage)
786 public void receivedMessage(FcpConnection fcpConnection, FcpMessage fcpMessage) {
791 * @see net.pterodactylus.fcp.FcpListener#receivedNodeData(net.pterodactylus.fcp.FcpConnection,
792 * net.pterodactylus.fcp.NodeData)
794 public void receivedNodeData(FcpConnection fcpConnection, NodeData nodeData) {
799 * @see net.pterodactylus.fcp.FcpListener#receivedNodeHello(net.pterodactylus.fcp.FcpConnection,
800 * net.pterodactylus.fcp.NodeHello)
802 @SuppressWarnings("synthetic-access")
803 public void receivedNodeHello(FcpConnection fcpConnection, NodeHello nodeHello) {
804 if (fcpConnection != HighLevelClient.this.fcpConnection) {
807 synchronized (syncObject) {
808 connectCallback.getIntermediaryResult().setFailed(false);
809 connectCallback.setDone();
810 connectCallback = null;
812 fireClientConnected();
816 * @see net.pterodactylus.fcp.FcpListener#receivedPeer(net.pterodactylus.fcp.FcpConnection,
817 * net.pterodactylus.fcp.Peer)
819 @SuppressWarnings("synthetic-access")
820 public void receivedPeer(FcpConnection fcpConnection, Peer peer) {
821 if (fcpConnection != HighLevelClient.this.fcpConnection) {
824 String identifier = peer.getIdentifier();
825 if (identifier == null) {
828 HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.get(identifier);
829 if (peerListCallback != null) {
830 peerListCallback.getIntermediaryResult().addPeer(peer);
833 HighLevelCallback<PeerResult> peerResult = peerCallbacks.remove(identifier);
834 if (peerResult != null) {
835 peerResult.getIntermediaryResult().setPeer(peer);
836 peerResult.setDone();
839 logger.warning("got Peer message with unknown identifier: " + identifier);
843 * @see net.pterodactylus.fcp.FcpListener#receivedPeerNote(net.pterodactylus.fcp.FcpConnection,
844 * net.pterodactylus.fcp.PeerNote)
846 public void receivedPeerNote(FcpConnection fcpConnection, PeerNote peerNote) {
851 * @see net.pterodactylus.fcp.FcpListener#receivedPeerRemoved(net.pterodactylus.fcp.FcpConnection,
852 * net.pterodactylus.fcp.PeerRemoved)
854 public void receivedPeerRemoved(FcpConnection fcpConnection, PeerRemoved peerRemoved) {
859 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentGet(net.pterodactylus.fcp.FcpConnection,
860 * net.pterodactylus.fcp.PersistentGet)
862 @SuppressWarnings("synthetic-access")
863 public void receivedPersistentGet(FcpConnection fcpConnection, PersistentGet persistentGet) {
864 if (fcpConnection != HighLevelClient.this.fcpConnection) {
867 synchronized (syncObject) {
868 if (requestListCallback != null) {
869 RequestListResult requestListResult = requestListCallback.getIntermediaryResult();
870 requestListResult.addRequestResult(new GetRequestResult(persistentGet));
874 String identifier = persistentGet.getIdentifier();
875 if (downloadCallbacks.containsKey(identifier)) {
882 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPut(net.pterodactylus.fcp.FcpConnection,
883 * net.pterodactylus.fcp.PersistentPut)
885 @SuppressWarnings("synthetic-access")
886 public void receivedPersistentPut(FcpConnection fcpConnection, PersistentPut persistentPut) {
887 if (fcpConnection != HighLevelClient.this.fcpConnection) {
890 synchronized (syncObject) {
891 if (requestListCallback != null) {
892 RequestListResult requestListResult = requestListCallback.getIntermediaryResult();
893 requestListResult.addRequestResult(new PutRequestResult(persistentPut));
900 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPutDir(net.pterodactylus.fcp.FcpConnection,
901 * net.pterodactylus.fcp.PersistentPutDir)
903 @SuppressWarnings("synthetic-access")
904 public void receivedPersistentPutDir(FcpConnection fcpConnection, PersistentPutDir persistentPutDir) {
905 if (fcpConnection != HighLevelClient.this.fcpConnection) {
908 synchronized (syncObject) {
909 if (requestListCallback != null) {
910 RequestListResult requestListResult = requestListCallback.getIntermediaryResult();
911 requestListResult.addRequestResult(new PutDirRequestResult(persistentPutDir));
918 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestModified(net.pterodactylus.fcp.FcpConnection,
919 * net.pterodactylus.fcp.PersistentRequestModified)
921 public void receivedPersistentRequestModified(FcpConnection fcpConnection, PersistentRequestModified persistentRequestModified) {
926 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestRemoved(net.pterodactylus.fcp.FcpConnection,
927 * net.pterodactylus.fcp.PersistentRequestRemoved)
929 public void receivedPersistentRequestRemoved(FcpConnection fcpConnection, PersistentRequestRemoved persistentRequestRemoved) {
934 * @see net.pterodactylus.fcp.FcpListener#receivedPluginInfo(net.pterodactylus.fcp.FcpConnection,
935 * net.pterodactylus.fcp.PluginInfo)
937 public void receivedPluginInfo(FcpConnection fcpConnection, PluginInfo pluginInfo) {
942 * @see net.pterodactylus.fcp.FcpListener#receivedProtocolError(net.pterodactylus.fcp.FcpConnection,
943 * net.pterodactylus.fcp.ProtocolError)
945 @SuppressWarnings("synthetic-access")
946 public void receivedProtocolError(FcpConnection fcpConnection, ProtocolError protocolError) {
947 if (fcpConnection != HighLevelClient.this.fcpConnection) {
950 String identifier = protocolError.getIdentifier();
951 if (identifier == null) {
954 cancelIdentifier(identifier);
958 * @see net.pterodactylus.fcp.FcpListener#receivedPutFailed(net.pterodactylus.fcp.FcpConnection,
959 * net.pterodactylus.fcp.PutFailed)
961 public void receivedPutFailed(FcpConnection fcpConnection, PutFailed putFailed) {
966 * @see net.pterodactylus.fcp.FcpListener#receivedPutFetchable(net.pterodactylus.fcp.FcpConnection,
967 * net.pterodactylus.fcp.PutFetchable)
969 public void receivedPutFetchable(FcpConnection fcpConnection, PutFetchable putFetchable) {
974 * @see net.pterodactylus.fcp.FcpListener#receivedPutSuccessful(net.pterodactylus.fcp.FcpConnection,
975 * net.pterodactylus.fcp.PutSuccessful)
977 public void receivedPutSuccessful(FcpConnection fcpConnection, PutSuccessful putSuccessful) {
982 * @see net.pterodactylus.fcp.FcpListener#receivedSSKKeypair(net.pterodactylus.fcp.FcpConnection,
983 * net.pterodactylus.fcp.SSKKeypair)
985 @SuppressWarnings("synthetic-access")
986 public void receivedSSKKeypair(FcpConnection fcpConnection, SSKKeypair sskKeypair) {
987 if (fcpConnection != HighLevelClient.this.fcpConnection) {
990 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(sskKeypair.getIdentifier());
991 if (keyGenerationCallback == null) {
994 KeyGenerationResult keyGenerationResult = keyGenerationCallback.getIntermediaryResult();
995 keyGenerationResult.setInsertURI(sskKeypair.getInsertURI());
996 keyGenerationResult.setRequestURI(sskKeypair.getRequestURI());
997 keyGenerationCallback.setDone();
1001 * @see net.pterodactylus.fcp.FcpListener#receivedSimpleProgress(net.pterodactylus.fcp.FcpConnection,
1002 * net.pterodactylus.fcp.SimpleProgress)
1004 @SuppressWarnings("synthetic-access")
1005 public void receivedSimpleProgress(FcpConnection fcpConnection, SimpleProgress simpleProgress) {
1006 if (fcpConnection != HighLevelClient.this.fcpConnection) {
1009 String identifier = simpleProgress.getIdentifier();
1010 HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.get(identifier);
1011 if (downloadCallback != null) {
1012 DownloadResult downloadResult = downloadCallback.getIntermediaryResult();
1013 downloadResult.setTotalBlocks(simpleProgress.getTotal());
1014 downloadResult.setRequiredBlocks(simpleProgress.getRequired());
1015 downloadResult.setSuccessfulBlocks(simpleProgress.getSucceeded());
1016 downloadResult.setFailedBlocks(simpleProgress.getFailed());
1017 downloadResult.setFatallyFailedBlocks(simpleProgress.getFatallyFailed());
1018 downloadResult.setTotalFinalized(simpleProgress.isFinalizedTotal());
1019 downloadCallback.progressUpdated();
1022 /* unknown identifier? */
1023 logger.warning("unknown identifier for SimpleProgress: " + identifier);
1027 * @see net.pterodactylus.fcp.FcpListener#receivedStartedCompression(net.pterodactylus.fcp.FcpConnection,
1028 * net.pterodactylus.fcp.StartedCompression)
1030 public void receivedStartedCompression(FcpConnection fcpConnection, StartedCompression startedCompression) {
1035 * @see net.pterodactylus.fcp.FcpListener#receivedSubscribedUSKUpdate(net.pterodactylus.fcp.FcpConnection,
1036 * net.pterodactylus.fcp.SubscribedUSKUpdate)
1038 public void receivedSubscribedUSKUpdate(FcpConnection fcpConnection, SubscribedUSKUpdate subscribedUSKUpdate) {
1043 * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAComplete(net.pterodactylus.fcp.FcpConnection,
1044 * net.pterodactylus.fcp.TestDDAComplete)
1046 @SuppressWarnings("synthetic-access")
1047 public void receivedTestDDAComplete(FcpConnection fcpConnection, TestDDAComplete testDDAComplete) {
1048 if (fcpConnection != HighLevelClient.this.fcpConnection) {
1051 String directory = testDDAComplete.getDirectory();
1052 if (directory == null) {
1055 HighLevelCallback<DirectDiskAccessResult> directDiskAccessCallback = directDiskAccessCallbacks.remove(directory);
1056 DirectDiskAccessResult directDiskAccessResult = directDiskAccessCallback.getIntermediaryResult();
1057 cleanFiles(directDiskAccessResult);
1058 directDiskAccessResult.setReadAllowed(testDDAComplete.isReadDirectoryAllowed());
1059 directDiskAccessResult.setWriteAllowed(testDDAComplete.isWriteDirectoryAllowed());
1060 directDiskAccessCallback.setDone();
1064 * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAReply(net.pterodactylus.fcp.FcpConnection,
1065 * net.pterodactylus.fcp.TestDDAReply)
1067 @SuppressWarnings("synthetic-access")
1068 public void receivedTestDDAReply(FcpConnection fcpConnection, TestDDAReply testDDAReply) {
1069 if (fcpConnection != HighLevelClient.this.fcpConnection) {
1072 String directory = testDDAReply.getDirectory();
1073 if (directory == null) {
1076 DirectDiskAccessResult directDiskAccessResult = directDiskAccessCallbacks.get(directory).getIntermediaryResult();
1077 String readFilename = testDDAReply.getReadFilename();
1078 String readContent = readContent(readFilename);
1079 String writeFilename = testDDAReply.getWriteFilename();
1080 String writeContent = testDDAReply.getContentToWrite();
1081 writeContent(directDiskAccessResult, writeFilename, writeContent);
1082 TestDDAResponse testDDAResponse = new TestDDAResponse(directory, readContent);
1084 fcpConnection.sendMessage(testDDAResponse);
1085 } catch (IOException e) {
1086 /* swallow. I’m verry unhappy about this. */
1091 * @see net.pterodactylus.fcp.FcpListener#receivedURIGenerated(net.pterodactylus.fcp.FcpConnection,
1092 * net.pterodactylus.fcp.URIGenerated)
1094 public void receivedURIGenerated(FcpConnection fcpConnection, URIGenerated uriGenerated) {
1099 * @see net.pterodactylus.fcp.FcpListener#receivedUnknownNodeIdentifier(net.pterodactylus.fcp.FcpConnection,
1100 * net.pterodactylus.fcp.UnknownNodeIdentifier)
1102 public void receivedUnknownNodeIdentifier(FcpConnection fcpConnection, UnknownNodeIdentifier unknownNodeIdentifier) {
1107 * @see net.pterodactylus.fcp.FcpListener#receivedUnknownPeerNoteType(net.pterodactylus.fcp.FcpConnection,
1108 * net.pterodactylus.fcp.UnknownPeerNoteType)
1110 public void receivedUnknownPeerNoteType(FcpConnection fcpConnection, UnknownPeerNoteType unknownPeerNoteType) {
1115 * @see net.pterodactylus.fcp.FcpListener#receviedFinishedCompression(net.pterodactylus.fcp.FcpConnection,
1116 * net.pterodactylus.fcp.FinishedCompression)
1118 public void receviedFinishedCompression(FcpConnection fcpConnection, FinishedCompression finishedCompression) {