1b52e728368d2078c72805b98488306bc792cea7
[jFCPlib.git] / src / net / pterodactylus / fcp / highlevel / HighLevelClient.java
1 /*
2  * fcplib - HighLevelClient.java -
3  * Copyright © 2008 David Roden
4  *
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.
9  *
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.
14  *
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.
18  */
19
20 package net.pterodactylus.fcp.highlevel;
21
22 import java.io.BufferedReader;
23 import java.io.File;
24 import java.io.FileReader;
25 import java.io.FileWriter;
26 import java.io.IOException;
27 import java.net.InetAddress;
28 import java.net.URL;
29 import java.net.UnknownHostException;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.Map;
33 import java.util.Map.Entry;
34 import java.util.logging.Logger;
35
36 import net.pterodactylus.fcp.AddPeer;
37 import net.pterodactylus.fcp.AllData;
38 import net.pterodactylus.fcp.ClientGet;
39 import net.pterodactylus.fcp.ClientHello;
40 import net.pterodactylus.fcp.CloseConnectionDuplicateClientName;
41 import net.pterodactylus.fcp.ConfigData;
42 import net.pterodactylus.fcp.DataFound;
43 import net.pterodactylus.fcp.EndListPeerNotes;
44 import net.pterodactylus.fcp.EndListPeers;
45 import net.pterodactylus.fcp.EndListPersistentRequests;
46 import net.pterodactylus.fcp.FCPPluginReply;
47 import net.pterodactylus.fcp.FcpConnection;
48 import net.pterodactylus.fcp.FcpListener;
49 import net.pterodactylus.fcp.FcpMessage;
50 import net.pterodactylus.fcp.FcpUtils;
51 import net.pterodactylus.fcp.FinishedCompression;
52 import net.pterodactylus.fcp.GenerateSSK;
53 import net.pterodactylus.fcp.GetFailed;
54 import net.pterodactylus.fcp.IdentifierCollision;
55 import net.pterodactylus.fcp.ListPeers;
56 import net.pterodactylus.fcp.NodeData;
57 import net.pterodactylus.fcp.NodeHello;
58 import net.pterodactylus.fcp.NodeRef;
59 import net.pterodactylus.fcp.Peer;
60 import net.pterodactylus.fcp.PeerNote;
61 import net.pterodactylus.fcp.PeerRemoved;
62 import net.pterodactylus.fcp.PersistentGet;
63 import net.pterodactylus.fcp.PersistentPut;
64 import net.pterodactylus.fcp.PersistentPutDir;
65 import net.pterodactylus.fcp.PersistentRequestModified;
66 import net.pterodactylus.fcp.PersistentRequestRemoved;
67 import net.pterodactylus.fcp.PluginInfo;
68 import net.pterodactylus.fcp.ProtocolError;
69 import net.pterodactylus.fcp.PutFailed;
70 import net.pterodactylus.fcp.PutFetchable;
71 import net.pterodactylus.fcp.PutSuccessful;
72 import net.pterodactylus.fcp.ReturnType;
73 import net.pterodactylus.fcp.SSKKeypair;
74 import net.pterodactylus.fcp.SimpleProgress;
75 import net.pterodactylus.fcp.StartedCompression;
76 import net.pterodactylus.fcp.SubscribedUSKUpdate;
77 import net.pterodactylus.fcp.TestDDAComplete;
78 import net.pterodactylus.fcp.TestDDAReply;
79 import net.pterodactylus.fcp.TestDDARequest;
80 import net.pterodactylus.fcp.TestDDAResponse;
81 import net.pterodactylus.fcp.URIGenerated;
82 import net.pterodactylus.fcp.UnknownNodeIdentifier;
83 import net.pterodactylus.fcp.UnknownPeerNoteType;
84
85 /**
86  * A high-level client that allows simple yet full-featured access to a Freenet
87  * node.
88  *
89  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
90  * @version $Id$
91  */
92 public class HighLevelClient {
93
94         /** Logger. */
95         private static final Logger logger = Logger.getLogger(HighLevelClient.class.getName());
96
97         /** Object for internal synchronization. */
98         private final Object syncObject = new Object();
99
100         /** The name of the client. */
101         private final String clientName;
102
103         /** The address of the node. */
104         private InetAddress address;
105
106         /** The port number of the node. */
107         private int port;
108
109         /** The FCP connection to the node. */
110         private FcpConnection fcpConnection;
111
112         /** The listener for the connection. */
113         private HighLevelClientFcpListener highLevelClientFcpListener = new HighLevelClientFcpListener();
114
115         /** The callback for {@link #connect()}. */
116         private HighLevelCallback<ConnectResult> connectCallback;
117
118         /** Mapping from request identifiers to callbacks. */
119         private Map<String, HighLevelCallback<KeyGenerationResult>> keyGenerationCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<KeyGenerationResult>>());
120
121         /** Mapping from request identifier to peer list callbacks. */
122         private Map<String, HighLevelCallback<PeerListResult>> peerListCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<PeerListResult>>());
123
124         /** Mapping from request identifier to peer callbacks. */
125         private Map<String, HighLevelCallback<PeerResult>> peerCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<PeerResult>>());
126
127         /** Mapping from directories to DDA callbacks. */
128         private Map<String, HighLevelCallback<DirectDiskAccessResult>> directDiskAccessCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<DirectDiskAccessResult>>());
129
130         /** Mapping from request identifiers to download callbacks. */
131         private Map<String, HighLevelProgressCallback<DownloadResult>> downloadCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelProgressCallback<DownloadResult>>());
132
133         /**
134          * Creates a new high-level client that connects to a node on
135          * <code>localhost</code>.
136          *
137          * @param clientName
138          *            The name of the client
139          * @throws UnknownHostException
140          *             if the hostname of the node can not be resolved.
141          */
142         public HighLevelClient(String clientName) throws UnknownHostException {
143                 this(clientName, "localhost");
144         }
145
146         /**
147          * Creates a new high-level client that connects to a node on the given
148          * host.
149          *
150          * @param clientName
151          *            The name of the client
152          * @param host
153          *            The hostname of the node
154          * @throws UnknownHostException
155          *             if the hostname of the node can not be resolved.
156          */
157         public HighLevelClient(String clientName, String host) throws UnknownHostException {
158                 this(clientName, host, FcpConnection.DEFAULT_PORT);
159         }
160
161         /**
162          * Creates a new high-level client that connects to a node on the given
163          * host.
164          *
165          * @param clientName
166          *            The name of the client
167          * @param host
168          *            The hostname of the node
169          * @param port
170          *            The port number of the node
171          * @throws UnknownHostException
172          *             if the hostname of the node can not be resolved.
173          */
174         public HighLevelClient(String clientName, String host, int port) throws UnknownHostException {
175                 this(clientName, InetAddress.getByName(host), port);
176         }
177
178         /**
179          * Creates a new high-level client that connects to a node at the given
180          * address.
181          *
182          * @param clientName
183          *            The name of the client
184          * @param address
185          *            The address of the node
186          * @param port
187          *            The port number of the node
188          */
189         public HighLevelClient(String clientName, InetAddress address, int port) {
190                 this.clientName = clientName;
191                 this.address = address;
192                 this.port = port;
193         }
194
195         //
196         // ACCESSORS
197         //
198
199         /**
200          * Returns the FCP connection that backs this high-level client. This method
201          * should be used with care as fiddling around with the FCP connection can
202          * easily break the high-level client if you don’t know what you’re doing!
203          *
204          * @return The FCP connection of this client
205          */
206         public FcpConnection getFcpConnection() {
207                 return fcpConnection;
208         }
209
210         //
211         // ACTIONS
212         //
213
214         /**
215          * Connects the client.
216          *
217          * @return A callback with a connection result
218          * @throws IOException
219          *             if an I/O error occurs communicating with the node
220          */
221         public HighLevelCallback<ConnectResult> connect() throws IOException {
222                 fcpConnection = new FcpConnection(address, port);
223                 fcpConnection.addFcpListener(highLevelClientFcpListener);
224                 ClientHello clientHello = new ClientHello(clientName);
225                 connectCallback = new HighLevelCallback<ConnectResult>(new ConnectResult());
226                 fcpConnection.sendMessage(clientHello);
227                 return connectCallback;
228         }
229
230         /**
231          * Disconnects the client from the node.
232          */
233         public void disconnect() {
234                 fcpConnection.disconnect();
235         }
236
237         /**
238          * Generates a new SSK keypair.
239          *
240          * @return A callback with the keypair
241          * @throws IOException
242          *             if an I/O error occurs communicating with the node
243          */
244         public HighLevelCallback<KeyGenerationResult> generateKey() throws IOException {
245                 String identifier = generateIdentifier("generateSSK");
246                 GenerateSSK generateSSK = new GenerateSSK(identifier);
247                 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = new HighLevelCallback<KeyGenerationResult>(new KeyGenerationResult(identifier));
248                 keyGenerationCallbacks.put(identifier, keyGenerationCallback);
249                 fcpConnection.sendMessage(generateSSK);
250                 return keyGenerationCallback;
251         }
252
253         /**
254          * Gets a list of all peers from the node.
255          *
256          * @return A callback with the peer list
257          * @throws IOException
258          *             if an I/O error occurs with the node
259          */
260         public HighLevelCallback<PeerListResult> getPeers() throws IOException {
261                 String identifier = generateIdentifier("listPeers");
262                 ListPeers listPeers = new ListPeers(identifier, true, true);
263                 HighLevelCallback<PeerListResult> peerListCallback = new HighLevelCallback<PeerListResult>(new PeerListResult(identifier));
264                 peerListCallbacks.put(identifier, peerListCallback);
265                 fcpConnection.sendMessage(listPeers);
266                 return peerListCallback;
267         }
268
269         /**
270          * Adds the peer whose noderef is stored in the given file.
271          *
272          * @param nodeRefFile
273          *            The name of the file the peer’s noderef is stored in
274          * @return A peer callback
275          * @throws IOException
276          *             if an I/O error occurs communicating with the node
277          */
278         public HighLevelCallback<PeerResult> addPeer(String nodeRefFile) throws IOException {
279                 String identifier = generateIdentifier("addPeer");
280                 AddPeer addPeer = new AddPeer(nodeRefFile);
281                 HighLevelCallback<PeerResult> peerCallback = new HighLevelCallback<PeerResult>(new PeerResult(identifier));
282                 peerCallbacks.put(identifier, peerCallback);
283                 fcpConnection.sendMessage(addPeer);
284                 return peerCallback;
285         }
286
287         /**
288          * Adds the peer whose noderef is stored in the given file.
289          *
290          * @param nodeRefURL
291          *            The URL where the peer’s noderef is stored
292          * @return A peer callback
293          * @throws IOException
294          *             if an I/O error occurs communicating with the node
295          */
296         public HighLevelCallback<PeerResult> addPeer(URL nodeRefURL) throws IOException {
297                 String identifier = generateIdentifier("addPeer");
298                 AddPeer addPeer = new AddPeer(nodeRefURL);
299                 HighLevelCallback<PeerResult> peerCallback = new HighLevelCallback<PeerResult>(new PeerResult(identifier));
300                 peerCallbacks.put(identifier, peerCallback);
301                 fcpConnection.sendMessage(addPeer);
302                 return peerCallback;
303         }
304
305         /**
306          * Adds the peer whose noderef is stored in the given file.
307          *
308          * @param nodeRef
309          *            The peer’s noderef
310          * @return A peer callback
311          * @throws IOException
312          *             if an I/O error occurs communicating with the node
313          */
314         public HighLevelCallback<PeerResult> addPeer(NodeRef nodeRef) throws IOException {
315                 String identifier = generateIdentifier("addPeer");
316                 AddPeer addPeer = new AddPeer(nodeRef);
317                 HighLevelCallback<PeerResult> peerCallback = new HighLevelCallback<PeerResult>(new PeerResult(identifier));
318                 peerCallbacks.put(identifier, peerCallback);
319                 fcpConnection.sendMessage(addPeer);
320                 return peerCallback;
321         }
322
323         /**
324          * Checks whether direct disk access for the given directory is possible.
325          * You have to perform this check before you can upload or download anything
326          * from or the disk directly!
327          *
328          * @param directory
329          *            The directory to check
330          * @param wantRead
331          *            Whether you want to read the given directory
332          * @param wantWrite
333          *            Whether you want to write to the given directory
334          * @return A direct disk access callback
335          * @throws IOException
336          */
337         public HighLevelCallback<DirectDiskAccessResult> checkDirectDiskAccess(String directory, boolean wantRead, boolean wantWrite) throws IOException {
338                 TestDDARequest testDDARequest = new TestDDARequest(directory, wantRead, wantWrite);
339                 HighLevelCallback<DirectDiskAccessResult> directDiskAccessCallback = new HighLevelCallback<DirectDiskAccessResult>(new DirectDiskAccessResult(directory));
340                 directDiskAccessCallbacks.put(directory, directDiskAccessCallback);
341                 fcpConnection.sendMessage(testDDARequest);
342                 return directDiskAccessCallback;
343         }
344
345         /**
346          * Starts a download. Files can either be download to disk or streamed from
347          * the node. When downloading to disk you have to perform a direct disk
348          * access check for the directory you want to put the downloaded file in!
349          *
350          * @see #checkDirectDiskAccess(String, boolean, boolean)
351          * @param uri
352          *            The URI to get
353          * @param filename
354          *            The filename to save the data to, or <code>null</code> to
355          *            retrieve the data as InputStream from the
356          *            {@link DownloadResult}
357          * @param global
358          *            Whether to put the download on the global queue
359          * @return A download result
360          * @throws IOException
361          *             if an I/O error occurs communicating with the node
362          */
363         public HighLevelProgressCallback<DownloadResult> download(String uri, String filename, boolean global) throws IOException {
364                 String identifier = generateIdentifier("download");
365                 ClientGet clientGet = new ClientGet(uri, identifier, (filename == null) ? ReturnType.direct : ReturnType.disk);
366                 clientGet.setGlobal(global);
367                 HighLevelProgressCallback<DownloadResult> downloadCallback = new HighLevelProgressCallback<DownloadResult>(new DownloadResult(identifier));
368                 downloadCallbacks.put(identifier, downloadCallback);
369                 fcpConnection.sendMessage(clientGet);
370                 return downloadCallback;
371         }
372
373         //
374         // PRIVATE METHODS
375         //
376
377         /**
378          * Generates an identifier for the given function.
379          *
380          * @param function
381          *            The name of the function
382          * @return An identifier
383          */
384         private String generateIdentifier(String function) {
385                 return "jFCPlib-" + function + "-" + System.currentTimeMillis();
386         }
387
388         /**
389          * FCP listener for {@link HighLevelClient}.
390          *
391          * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
392          * @version $Id$
393          */
394         private class HighLevelClientFcpListener implements FcpListener {
395
396                 /** Mapping from directory to written file (for cleanup). */
397                 private final Map<DirectDiskAccessResult, String> writtenFiles = new HashMap<DirectDiskAccessResult, String>();
398
399                 /**
400                  * Creates a new FCP listener for {@link HighLevelClient}.
401                  */
402                 HighLevelClientFcpListener() {
403                         /* do nothing. */
404                 }
405
406                 //
407                 // PRIVATE METHODS
408                 //
409
410                 /**
411                  * Searches all callback collections for a callback with the given
412                  * identifier and cancels it.
413                  *
414                  * @param identifier
415                  *            The identifier to search for, or <code>null</code> to
416                  *            cancel all pending requests
417                  */
418                 @SuppressWarnings("synthetic-access")
419                 private void cancelIdentifier(String identifier) {
420                         synchronized (syncObject) {
421                                 if (connectCallback != null) {
422                                         connectCallback.getIntermediaryResult().setFailed(true);
423                                         connectCallback.setDone();
424                                         connectCallback = null;
425                                 }
426                         }
427                         if (identifier == null) {
428                                 /* key generation callbacks */
429                                 for (Entry<String, HighLevelCallback<KeyGenerationResult>> keyGenerationEntry: keyGenerationCallbacks.entrySet()) {
430                                         keyGenerationEntry.getValue().getIntermediaryResult().setFailed(true);
431                                         keyGenerationEntry.getValue().setDone();
432                                 }
433                                 keyGenerationCallbacks.clear();
434                                 /* peer list callbacks. */
435                                 for (Entry<String, HighLevelCallback<PeerListResult>> peerListEntry: peerListCallbacks.entrySet()) {
436                                         peerListEntry.getValue().getIntermediaryResult().setFailed(true);
437                                         peerListEntry.getValue().setDone();
438                                 }
439                                 peerListCallbacks.clear();
440                                 /* peer callbacks. */
441                                 for (Entry<String, HighLevelCallback<PeerResult>> peerEntry: peerCallbacks.entrySet()) {
442                                         peerEntry.getValue().getIntermediaryResult().setFailed(true);
443                                         peerEntry.getValue().setDone();
444                                 }
445                                 peerCallbacks.clear();
446                                 /* direct disk access callbacks. */
447                                 for (Entry<String, HighLevelCallback<DirectDiskAccessResult>> directDiskAccessEntry: directDiskAccessCallbacks.entrySet()) {
448                                         directDiskAccessEntry.getValue().getIntermediaryResult().setFailed(true);
449                                         directDiskAccessEntry.getValue().setDone();
450                                 }
451                                 directDiskAccessCallbacks.clear();
452                                 /* download callbacks. */
453                                 for (Entry<String, HighLevelProgressCallback<DownloadResult>> downloadEntry: downloadCallbacks.entrySet()) {
454                                         downloadEntry.getValue().getIntermediaryResult().setFailed(true);
455                                         downloadEntry.getValue().setDone();
456                                 }
457                                 downloadCallbacks.clear();
458                         } else {
459                                 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(identifier);
460                                 if (keyGenerationCallback != null) {
461                                         keyGenerationCallback.getIntermediaryResult().setFailed(true);
462                                         keyGenerationCallback.setDone();
463                                         return;
464                                 }
465                                 HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.remove(identifier);
466                                 if (peerListCallback != null) {
467                                         peerListCallback.getIntermediaryResult().setFailed(true);
468                                         peerListCallback.setDone();
469                                         return;
470                                 }
471                                 HighLevelCallback<PeerResult> peerCallback = peerCallbacks.remove(identifier);
472                                 if (peerCallback != null) {
473                                         peerCallback.getIntermediaryResult().setFailed(true);
474                                         peerCallback.setDone();
475                                         return;
476                                 }
477                                 HighLevelCallback<DirectDiskAccessResult> directDiskAccessCallback = directDiskAccessCallbacks.remove(identifier);
478                                 if (directDiskAccessCallback != null) {
479                                         directDiskAccessCallback.getIntermediaryResult().setFailed(true);
480                                         directDiskAccessCallback.setDone();
481                                         return;
482                                 }
483                                 HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.remove(identifier);
484                                 if (downloadCallback != null) {
485                                         downloadCallback.getIntermediaryResult().setFailed(true);
486                                         downloadCallback.setDone();
487                                         return;
488                                 }
489                         }
490                 }
491
492                 /**
493                  * Reads the given file and returns the first line of the file.
494                  *
495                  * @param readFilename
496                  *            The name of the file to read
497                  * @return The content of the file
498                  */
499                 private String readContent(String readFilename) {
500                         FileReader fileReader = null;
501                         BufferedReader bufferedFileReader = null;
502                         try {
503                                 fileReader = new FileReader(readFilename);
504                                 bufferedFileReader = new BufferedReader(fileReader);
505                                 String content = bufferedFileReader.readLine();
506                                 return content;
507                         } catch (IOException ioe1) {
508                                 /* swallow. */
509                         } finally {
510                                 FcpUtils.close(bufferedFileReader);
511                                 FcpUtils.close(fileReader);
512                         }
513                         return null;
514                 }
515
516                 /**
517                  * Writes the given content to the given file.
518                  *
519                  * @param directDiskAccessResult
520                  *            The DDA result
521                  * @param writeFilename
522                  *            The name of the file to write to
523                  * @param writeContent
524                  *            The content to write to the file
525                  */
526                 private void writeContent(DirectDiskAccessResult directDiskAccessResult, String writeFilename, String writeContent) {
527                         if ((writeFilename == null) || (writeContent == null)) {
528                                 return;
529                         }
530                         writtenFiles.put(directDiskAccessResult, writeFilename);
531                         FileWriter fileWriter = null;
532                         try {
533                                 fileWriter = new FileWriter(writeFilename);
534                                 fileWriter.write(writeContent);
535                         } catch (IOException ioe1) {
536                                 /* swallow. */
537                         } finally {
538                                 FcpUtils.close(fileWriter);
539                         }
540                 }
541
542                 /**
543                  * Cleans up any files that written for the given result.
544                  *
545                  * @param directDiskAccessResult
546                  *            The direct disk access result
547                  */
548                 @SuppressWarnings("synthetic-access")
549                 private void cleanFiles(DirectDiskAccessResult directDiskAccessResult) {
550                         String writeFilename = writtenFiles.remove(directDiskAccessResult);
551                         if (writeFilename != null) {
552                                 if (!new File(writeFilename).delete()) {
553                                         logger.warning("could not delete " + writeFilename);
554                                 }
555                         }
556                 }
557
558                 //
559                 // INTERFACE FcpListener
560                 //
561
562                 /**
563                  * @see net.pterodactylus.fcp.FcpListener#connectionClosed(net.pterodactylus.fcp.FcpConnection)
564                  */
565                 @SuppressWarnings("synthetic-access")
566                 public void connectionClosed(FcpConnection fcpConnection) {
567                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
568                                 return;
569                         }
570                         cancelIdentifier(null);
571                 }
572
573                 /**
574                  * @see net.pterodactylus.fcp.FcpListener#receivedAllData(net.pterodactylus.fcp.FcpConnection,
575                  *      net.pterodactylus.fcp.AllData)
576                  */
577                 public void receivedAllData(FcpConnection fcpConnection, AllData allData) {
578                         /* TODO */
579                 }
580
581                 /**
582                  * @see net.pterodactylus.fcp.FcpListener#receivedCloseConnectionDuplicateClientName(net.pterodactylus.fcp.FcpConnection,
583                  *      net.pterodactylus.fcp.CloseConnectionDuplicateClientName)
584                  */
585                 public void receivedCloseConnectionDuplicateClientName(FcpConnection fcpConnection, CloseConnectionDuplicateClientName closeConnectionDuplicateClientName) {
586                         /* TODO */
587                 }
588
589                 /**
590                  * @see net.pterodactylus.fcp.FcpListener#receivedConfigData(net.pterodactylus.fcp.FcpConnection,
591                  *      net.pterodactylus.fcp.ConfigData)
592                  */
593                 public void receivedConfigData(FcpConnection fcpConnection, ConfigData configData) {
594                         /* TODO */
595                 }
596
597                 /**
598                  * @see net.pterodactylus.fcp.FcpListener#receivedDataFound(net.pterodactylus.fcp.FcpConnection,
599                  *      net.pterodactylus.fcp.DataFound)
600                  */
601                 public void receivedDataFound(FcpConnection fcpConnection, DataFound dataFound) {
602                         /* TODO */
603                 }
604
605                 /**
606                  * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeerNotes(net.pterodactylus.fcp.FcpConnection,
607                  *      net.pterodactylus.fcp.EndListPeerNotes)
608                  */
609                 public void receivedEndListPeerNotes(FcpConnection fcpConnection, EndListPeerNotes endListPeerNotes) {
610                         /* TODO */
611                 }
612
613                 /**
614                  * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeers(net.pterodactylus.fcp.FcpConnection,
615                  *      net.pterodactylus.fcp.EndListPeers)
616                  */
617                 @SuppressWarnings("synthetic-access")
618                 public void receivedEndListPeers(FcpConnection fcpConnection, EndListPeers endListPeers) {
619                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
620                                 return;
621                         }
622                         String identifier = endListPeers.getIdentifier();
623                         HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.remove(identifier);
624                         if (peerListCallback == null) {
625                                 return;
626                         }
627                         peerListCallback.setDone();
628                 }
629
630                 /**
631                  * @see net.pterodactylus.fcp.FcpListener#receivedEndListPersistentRequests(net.pterodactylus.fcp.FcpConnection,
632                  *      net.pterodactylus.fcp.EndListPersistentRequests)
633                  */
634                 public void receivedEndListPersistentRequests(FcpConnection fcpConnection, EndListPersistentRequests endListPersistentRequests) {
635                         /* TODO */
636                 }
637
638                 /**
639                  * @see net.pterodactylus.fcp.FcpListener#receivedFCPPluginReply(net.pterodactylus.fcp.FcpConnection,
640                  *      net.pterodactylus.fcp.FCPPluginReply)
641                  */
642                 public void receivedFCPPluginReply(FcpConnection fcpConnection, FCPPluginReply fcpPluginReply) {
643                         /* TODO */
644                 }
645
646                 /**
647                  * @see net.pterodactylus.fcp.FcpListener#receivedGetFailed(net.pterodactylus.fcp.FcpConnection,
648                  *      net.pterodactylus.fcp.GetFailed)
649                  */
650                 @SuppressWarnings("synthetic-access")
651                 public void receivedGetFailed(FcpConnection fcpConnection, GetFailed getFailed) {
652                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
653                                 return;
654                         }
655                         String identifier = getFailed.getIdentifier();
656                         HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.remove(identifier);
657                         if (downloadCallback != null) {
658                                 downloadCallback.getIntermediaryResult().setFailed(true);
659                                 downloadCallback.setDone();
660                                 return;
661                         }
662                         /* unknown identifier? */
663                         logger.warning("unknown identifier for GetFailed: " + identifier);
664                 }
665
666                 /**
667                  * @see net.pterodactylus.fcp.FcpListener#receivedIdentifierCollision(net.pterodactylus.fcp.FcpConnection,
668                  *      net.pterodactylus.fcp.IdentifierCollision)
669                  */
670                 public void receivedIdentifierCollision(FcpConnection fcpConnection, IdentifierCollision identifierCollision) {
671                         /* TODO */
672                 }
673
674                 /**
675                  * @see net.pterodactylus.fcp.FcpListener#receivedMessage(net.pterodactylus.fcp.FcpConnection,
676                  *      net.pterodactylus.fcp.FcpMessage)
677                  */
678                 public void receivedMessage(FcpConnection fcpConnection, FcpMessage fcpMessage) {
679                         /* TODO */
680                 }
681
682                 /**
683                  * @see net.pterodactylus.fcp.FcpListener#receivedNodeData(net.pterodactylus.fcp.FcpConnection,
684                  *      net.pterodactylus.fcp.NodeData)
685                  */
686                 public void receivedNodeData(FcpConnection fcpConnection, NodeData nodeData) {
687                         /* TODO */
688                 }
689
690                 /**
691                  * @see net.pterodactylus.fcp.FcpListener#receivedNodeHello(net.pterodactylus.fcp.FcpConnection,
692                  *      net.pterodactylus.fcp.NodeHello)
693                  */
694                 @SuppressWarnings("synthetic-access")
695                 public void receivedNodeHello(FcpConnection fcpConnection, NodeHello nodeHello) {
696                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
697                                 return;
698                         }
699                         synchronized (syncObject) {
700                                 connectCallback.getIntermediaryResult().setFailed(false);
701                                 connectCallback.setDone();
702                                 connectCallback = null;
703                         }
704                 }
705
706                 /**
707                  * @see net.pterodactylus.fcp.FcpListener#receivedPeer(net.pterodactylus.fcp.FcpConnection,
708                  *      net.pterodactylus.fcp.Peer)
709                  */
710                 @SuppressWarnings("synthetic-access")
711                 public void receivedPeer(FcpConnection fcpConnection, Peer peer) {
712                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
713                                 return;
714                         }
715                         String identifier = peer.getIdentifier();
716                         if (identifier == null) {
717                                 return;
718                         }
719                         HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.get(identifier);
720                         if (peerListCallback != null) {
721                                 peerListCallback.getIntermediaryResult().addPeer(peer);
722                                 return;
723                         }
724                         HighLevelCallback<PeerResult> peerResult = peerCallbacks.remove(identifier);
725                         if (peerResult != null) {
726                                 peerResult.getIntermediaryResult().setPeer(peer);
727                                 peerResult.setDone();
728                                 return;
729                         }
730                         logger.warning("got Peer message with unknown identifier: " + identifier);
731                 }
732
733                 /**
734                  * @see net.pterodactylus.fcp.FcpListener#receivedPeerNote(net.pterodactylus.fcp.FcpConnection,
735                  *      net.pterodactylus.fcp.PeerNote)
736                  */
737                 public void receivedPeerNote(FcpConnection fcpConnection, PeerNote peerNote) {
738                         /* TODO */
739                 }
740
741                 /**
742                  * @see net.pterodactylus.fcp.FcpListener#receivedPeerRemoved(net.pterodactylus.fcp.FcpConnection,
743                  *      net.pterodactylus.fcp.PeerRemoved)
744                  */
745                 public void receivedPeerRemoved(FcpConnection fcpConnection, PeerRemoved peerRemoved) {
746                         /* TODO */
747                 }
748
749                 /**
750                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentGet(net.pterodactylus.fcp.FcpConnection,
751                  *      net.pterodactylus.fcp.PersistentGet)
752                  */
753                 @SuppressWarnings("synthetic-access")
754                 public void receivedPersistentGet(FcpConnection fcpConnection, PersistentGet persistentGet) {
755                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
756                                 return;
757                         }
758                         String identifier = persistentGet.getIdentifier();
759                         if (downloadCallbacks.containsKey(identifier)) {
760                                 /* ignore, because a download does not care about this. */
761                                 return;
762                         }
763                 }
764
765                 /**
766                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPut(net.pterodactylus.fcp.FcpConnection,
767                  *      net.pterodactylus.fcp.PersistentPut)
768                  */
769                 public void receivedPersistentPut(FcpConnection fcpConnection, PersistentPut persistentPut) {
770                         /* TODO */
771                 }
772
773                 /**
774                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPutDir(net.pterodactylus.fcp.FcpConnection,
775                  *      net.pterodactylus.fcp.PersistentPutDir)
776                  */
777                 public void receivedPersistentPutDir(FcpConnection fcpConnection, PersistentPutDir persistentPutDir) {
778                         /* TODO */
779                 }
780
781                 /**
782                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestModified(net.pterodactylus.fcp.FcpConnection,
783                  *      net.pterodactylus.fcp.PersistentRequestModified)
784                  */
785                 public void receivedPersistentRequestModified(FcpConnection fcpConnection, PersistentRequestModified persistentRequestModified) {
786                         /* TODO */
787                 }
788
789                 /**
790                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestRemoved(net.pterodactylus.fcp.FcpConnection,
791                  *      net.pterodactylus.fcp.PersistentRequestRemoved)
792                  */
793                 public void receivedPersistentRequestRemoved(FcpConnection fcpConnection, PersistentRequestRemoved persistentRequestRemoved) {
794                         /* TODO */
795                 }
796
797                 /**
798                  * @see net.pterodactylus.fcp.FcpListener#receivedPluginInfo(net.pterodactylus.fcp.FcpConnection,
799                  *      net.pterodactylus.fcp.PluginInfo)
800                  */
801                 public void receivedPluginInfo(FcpConnection fcpConnection, PluginInfo pluginInfo) {
802                         /* TODO */
803                 }
804
805                 /**
806                  * @see net.pterodactylus.fcp.FcpListener#receivedProtocolError(net.pterodactylus.fcp.FcpConnection,
807                  *      net.pterodactylus.fcp.ProtocolError)
808                  */
809                 @SuppressWarnings("synthetic-access")
810                 public void receivedProtocolError(FcpConnection fcpConnection, ProtocolError protocolError) {
811                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
812                                 return;
813                         }
814                         String identifier = protocolError.getIdentifier();
815                         if (identifier == null) {
816                                 return;
817                         }
818                         cancelIdentifier(identifier);
819                 }
820
821                 /**
822                  * @see net.pterodactylus.fcp.FcpListener#receivedPutFailed(net.pterodactylus.fcp.FcpConnection,
823                  *      net.pterodactylus.fcp.PutFailed)
824                  */
825                 public void receivedPutFailed(FcpConnection fcpConnection, PutFailed putFailed) {
826                         /* TODO */
827                 }
828
829                 /**
830                  * @see net.pterodactylus.fcp.FcpListener#receivedPutFetchable(net.pterodactylus.fcp.FcpConnection,
831                  *      net.pterodactylus.fcp.PutFetchable)
832                  */
833                 public void receivedPutFetchable(FcpConnection fcpConnection, PutFetchable putFetchable) {
834                         /* TODO */
835                 }
836
837                 /**
838                  * @see net.pterodactylus.fcp.FcpListener#receivedPutSuccessful(net.pterodactylus.fcp.FcpConnection,
839                  *      net.pterodactylus.fcp.PutSuccessful)
840                  */
841                 public void receivedPutSuccessful(FcpConnection fcpConnection, PutSuccessful putSuccessful) {
842                         /* TODO */
843                 }
844
845                 /**
846                  * @see net.pterodactylus.fcp.FcpListener#receivedSSKKeypair(net.pterodactylus.fcp.FcpConnection,
847                  *      net.pterodactylus.fcp.SSKKeypair)
848                  */
849                 @SuppressWarnings("synthetic-access")
850                 public void receivedSSKKeypair(FcpConnection fcpConnection, SSKKeypair sskKeypair) {
851                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
852                                 return;
853                         }
854                         HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(sskKeypair.getIdentifier());
855                         if (keyGenerationCallback == null) {
856                                 return;
857                         }
858                         KeyGenerationResult keyGenerationResult = keyGenerationCallback.getIntermediaryResult();
859                         keyGenerationResult.setInsertURI(sskKeypair.getInsertURI());
860                         keyGenerationResult.setRequestURI(sskKeypair.getRequestURI());
861                         keyGenerationCallback.setDone();
862                 }
863
864                 /**
865                  * @see net.pterodactylus.fcp.FcpListener#receivedSimpleProgress(net.pterodactylus.fcp.FcpConnection,
866                  *      net.pterodactylus.fcp.SimpleProgress)
867                  */
868                 @SuppressWarnings("synthetic-access")
869                 public void receivedSimpleProgress(FcpConnection fcpConnection, SimpleProgress simpleProgress) {
870                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
871                                 return;
872                         }
873                         String identifier = simpleProgress.getIdentifier();
874                         HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.get(identifier);
875                         if (downloadCallback != null) {
876                                 DownloadResult downloadResult = downloadCallback.getIntermediaryResult();
877                                 downloadResult.setTotalBlocks(simpleProgress.getTotal());
878                                 downloadResult.setRequiredBlocks(simpleProgress.getRequired());
879                                 downloadResult.setSuccessfulBlocks(simpleProgress.getSucceeded());
880                                 downloadResult.setFailedBlocks(simpleProgress.getFailed());
881                                 downloadResult.setFatallyFailedBlocks(simpleProgress.getFatallyFailed());
882                                 downloadResult.setTotalFinalized(simpleProgress.isFinalizedTotal());
883                                 downloadCallback.progressUpdated();
884                                 return;
885                         }
886                         /* unknown identifier? */
887                         logger.warning("unknown identifier for SimpleProgress: " + identifier);
888                 }
889
890                 /**
891                  * @see net.pterodactylus.fcp.FcpListener#receivedStartedCompression(net.pterodactylus.fcp.FcpConnection,
892                  *      net.pterodactylus.fcp.StartedCompression)
893                  */
894                 public void receivedStartedCompression(FcpConnection fcpConnection, StartedCompression startedCompression) {
895                         /* TODO */
896                 }
897
898                 /**
899                  * @see net.pterodactylus.fcp.FcpListener#receivedSubscribedUSKUpdate(net.pterodactylus.fcp.FcpConnection,
900                  *      net.pterodactylus.fcp.SubscribedUSKUpdate)
901                  */
902                 public void receivedSubscribedUSKUpdate(FcpConnection fcpConnection, SubscribedUSKUpdate subscribedUSKUpdate) {
903                         /* TODO */
904                 }
905
906                 /**
907                  * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAComplete(net.pterodactylus.fcp.FcpConnection,
908                  *      net.pterodactylus.fcp.TestDDAComplete)
909                  */
910                 @SuppressWarnings("synthetic-access")
911                 public void receivedTestDDAComplete(FcpConnection fcpConnection, TestDDAComplete testDDAComplete) {
912                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
913                                 return;
914                         }
915                         String directory = testDDAComplete.getDirectory();
916                         if (directory == null) {
917                                 return;
918                         }
919                         HighLevelCallback<DirectDiskAccessResult> directDiskAccessCallback = directDiskAccessCallbacks.remove(directory);
920                         DirectDiskAccessResult directDiskAccessResult = directDiskAccessCallback.getIntermediaryResult();
921                         cleanFiles(directDiskAccessResult);
922                         directDiskAccessResult.setReadAllowed(testDDAComplete.isReadDirectoryAllowed());
923                         directDiskAccessResult.setWriteAllowed(testDDAComplete.isWriteDirectoryAllowed());
924                         directDiskAccessCallback.setDone();
925                 }
926
927                 /**
928                  * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAReply(net.pterodactylus.fcp.FcpConnection,
929                  *      net.pterodactylus.fcp.TestDDAReply)
930                  */
931                 @SuppressWarnings("synthetic-access")
932                 public void receivedTestDDAReply(FcpConnection fcpConnection, TestDDAReply testDDAReply) {
933                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
934                                 return;
935                         }
936                         String directory = testDDAReply.getDirectory();
937                         if (directory == null) {
938                                 return;
939                         }
940                         DirectDiskAccessResult directDiskAccessResult = directDiskAccessCallbacks.get(directory).getIntermediaryResult();
941                         String readFilename = testDDAReply.getReadFilename();
942                         String readContent = readContent(readFilename);
943                         String writeFilename = testDDAReply.getWriteFilename();
944                         String writeContent = testDDAReply.getContentToWrite();
945                         writeContent(directDiskAccessResult, writeFilename, writeContent);
946                         TestDDAResponse testDDAResponse = new TestDDAResponse(directory, readContent);
947                         try {
948                                 fcpConnection.sendMessage(testDDAResponse);
949                         } catch (IOException e) {
950                                 /* swallow. I’m verry unhappy about this. */
951                         }
952                 }
953
954                 /**
955                  * @see net.pterodactylus.fcp.FcpListener#receivedURIGenerated(net.pterodactylus.fcp.FcpConnection,
956                  *      net.pterodactylus.fcp.URIGenerated)
957                  */
958                 public void receivedURIGenerated(FcpConnection fcpConnection, URIGenerated uriGenerated) {
959                         /* TODO */
960                 }
961
962                 /**
963                  * @see net.pterodactylus.fcp.FcpListener#receivedUnknownNodeIdentifier(net.pterodactylus.fcp.FcpConnection,
964                  *      net.pterodactylus.fcp.UnknownNodeIdentifier)
965                  */
966                 public void receivedUnknownNodeIdentifier(FcpConnection fcpConnection, UnknownNodeIdentifier unknownNodeIdentifier) {
967                         /* TODO */
968                 }
969
970                 /**
971                  * @see net.pterodactylus.fcp.FcpListener#receivedUnknownPeerNoteType(net.pterodactylus.fcp.FcpConnection,
972                  *      net.pterodactylus.fcp.UnknownPeerNoteType)
973                  */
974                 public void receivedUnknownPeerNoteType(FcpConnection fcpConnection, UnknownPeerNoteType unknownPeerNoteType) {
975                         /* TODO */
976                 }
977
978                 /**
979                  * @see net.pterodactylus.fcp.FcpListener#receviedFinishedCompression(net.pterodactylus.fcp.FcpConnection,
980                  *      net.pterodactylus.fcp.FinishedCompression)
981                  */
982                 public void receviedFinishedCompression(FcpConnection fcpConnection, FinishedCompression finishedCompression) {
983                         /* TODO */
984                 }
985
986         }
987
988 }