import java.util.logging.Logger;
import net.pterodactylus.sone.core.Core.SoneStatus;
+import net.pterodactylus.sone.data.Client;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.Reply;
import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.util.collection.Pair;
import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.number.Numbers;
* The Sone to fetch
*/
public void fetchSone(Sone sone) {
+ fetchSone(sone, sone.getRequestUri());
+ }
+
+ /**
+ * Fetches the updated Sone. This method can be used to fetch a Sone from a
+ * specific URI (which happens when {@link Core#isSoneRescueMode() „Sone
+ * rescue mode“} is active).
+ *
+ * @param sone
+ * The Sone to fetch
+ * @param soneUri
+ * The URI to fetch the Sone from
+ */
+ public void fetchSone(Sone sone, FreenetURI soneUri) {
if (core.getSoneStatus(sone) == SoneStatus.downloading) {
return;
}
- logger.log(Level.FINE, "Starting fetch for Sone “%s” from %s…", new Object[] { sone, sone.getRequestUri().setMetaString(new String[] { "sone.xml" }) });
- FreenetURI requestUri = sone.getRequestUri().setMetaString(new String[] { "sone.xml" });
+ logger.log(Level.FINE, "Starting fetch for Sone “%s” from %s…", new Object[] { sone, soneUri });
+ FreenetURI requestUri = soneUri.setMetaString(new String[] { "sone.xml" });
core.setSoneStatus(sone, SoneStatus.downloading);
try {
- FetchResult fetchResult = freenetInterface.fetchUri(requestUri);
- if (fetchResult == null) {
+ Pair<FreenetURI, FetchResult> fetchResults = freenetInterface.fetchUri(requestUri);
+ if (fetchResults == null) {
/* TODO - mark Sone as bad. */
return;
}
- logger.log(Level.FINEST, "Got %d bytes back.", fetchResult.size());
- Sone parsedSone = parseSone(sone, fetchResult, requestUri);
+ logger.log(Level.FINEST, "Got %d bytes back.", fetchResults.getRight().size());
+ Sone parsedSone = parseSone(sone, fetchResults.getRight(), fetchResults.getLeft());
if (parsedSone != null) {
- core.addSone(parsedSone);
+ core.updateSone(parsedSone);
}
} finally {
core.setSoneStatus(sone, (sone.getTime() == 0) ? SoneStatus.unknown : SoneStatus.idle);
* @return The parsed Sone, or {@code null} if the Sone could not be parsed
*/
public Sone parseSone(Sone originalSone, FetchResult fetchResult, FreenetURI requestUri) {
- logger.log(Level.FINEST, "Persing FetchResult (%d bytes, %s) for %s…", new Object[] { fetchResult.size(), fetchResult.getMimeType(), originalSone });
+ logger.log(Level.FINEST, "Parsing FetchResult (%d bytes, %s) for %s…", new Object[] { fetchResult.size(), fetchResult.getMimeType(), originalSone });
Bucket soneBucket = fetchResult.asBucket();
InputStream soneInputStream = null;
try {
soneInputStream = soneBucket.getInputStream();
Sone parsedSone = parseSone(originalSone, soneInputStream);
if (parsedSone != null) {
- parsedSone.setRequestUri(requestUri.setMetaString(new String[0]));
+ parsedSone.setLatestEdition(requestUri.getEdition());
+ if (requestUri.getKeyType().equals("USK")) {
+ parsedSone.setRequestUri(requestUri.setMetaString(new String[0]));
+ } else {
+ parsedSone.setRequestUri(requestUri.setKeyType("USK").setDocName("Sone").setMetaString(new String[0]));
+ }
}
return parsedSone;
} catch (IOException ioe1) {
}
/**
- * Parses a Sone from the given input stream.
- *
- * @param soneInputStream
- * The input stream to parse the Sone from
- * @return The parsed Sone
- */
- public Sone parseSone(InputStream soneInputStream) {
- return parseSone(null, soneInputStream);
- }
-
- /**
- * Parses a Sone from the given input stream and updates the given Sone, or
- * creates a new Sone.
+ * Parses a Sone from the given input stream and creates a new Sone from the
+ * parsed data.
*
* @param originalSone
- * The Sone to update (may be {@code null})
+ * The Sone to update
* @param soneInputStream
* The input stream to parse the Sone from
* @return The parsed Sone
*/
public Sone parseSone(Sone originalSone, InputStream soneInputStream) {
/* TODO - impose a size limit? */
- Sone sone;
Document document;
/* XML parsing is not thread-safe. */
logger.log(Level.WARNING, "Could not parse XML for Sone %s!", new Object[] { originalSone });
return null;
}
+
+ Sone sone = new Sone(originalSone.getId()).setIdentity(originalSone.getIdentity());
+
SimpleXML soneXml;
try {
soneXml = SimpleXML.fromDocument(document);
} catch (NullPointerException npe1) {
/* for some reason, invalid XML can cause NPEs. */
- logger.log(Level.WARNING, "XML for Sone " + originalSone + " can not be parsed!", npe1);
+ logger.log(Level.WARNING, "XML for Sone " + sone + " can not be parsed!", npe1);
return null;
}
- /* check ID. */
- String soneId = soneXml.getValue("id", null);
- if ((originalSone != null) && !originalSone.getId().equals(soneId)) {
- /* TODO - mark Sone as bad. */
- logger.log(Level.WARNING, "Downloaded ID for Sone %s (%s) does not match known ID (%s)!", new Object[] { originalSone, originalSone.getId(), soneId });
- return null;
- }
-
- /* load Sone from core. */
- sone = originalSone;
- if (sone == null) {
- sone = core.getSone(soneId);
- }
-
- String soneName = soneXml.getValue("name", null);
- if (soneName == null) {
- /* TODO - mark Sone as bad. */
- logger.log(Level.WARNING, "Downloaded name for Sone %s was null!", new Object[] { sone });
- return null;
- }
- sone.setName(soneName);
-
String soneTime = soneXml.getValue("time", null);
if (soneTime == null) {
/* TODO - mark Sone as bad. */
return null;
}
+ SimpleXML clientXml = soneXml.getNode("client");
+ if (clientXml != null) {
+ String clientName = clientXml.getValue("name", null);
+ String clientVersion = clientXml.getValue("version", null);
+ if ((clientName == null) || (clientVersion == null)) {
+ logger.log(Level.WARNING, "Download Sone %s with client XML but missing name or version!", sone);
+ return null;
+ }
+ sone.setClient(new Client(clientName, clientVersion));
+ }
+
String soneRequestUri = soneXml.getValue("request-uri", null);
if (soneRequestUri != null) {
try {
if ((soneInsertUri != null) && (sone.getInsertUri() == null)) {
try {
sone.setInsertUri(new FreenetURI(soneInsertUri));
- sone.updateUris(Math.max(sone.getRequestUri().getSuggestedEdition(), sone.getInsertUri().getSuggestedEdition()));
+ sone.setLatestEdition(Math.max(sone.getRequestUri().getSuggestedEdition(), sone.getInsertUri().getSuggestedEdition()));
} catch (MalformedURLException mue1) {
/* TODO - mark Sone as bad. */
logger.log(Level.WARNING, "Downloaded Sone " + sone + " has invalid insert URI: " + soneInsertUri, mue1);
} else {
for (SimpleXML postXml : postsXml.getNodes("post")) {
String postId = postXml.getValue("id", null);
+ String postRecipientId = postXml.getValue("recipient", null);
String postTime = postXml.getValue("time", null);
String postText = postXml.getValue("text", null);
if ((postId == null) || (postTime == null) || (postText == null)) {
return null;
}
try {
- posts.add(core.getPost(postId).setSone(sone).setTime(Long.parseLong(postTime)).setText(postText));
+ Post post = core.getPost(postId).setSone(sone).setTime(Long.parseLong(postTime)).setText(postText);
+ if ((postRecipientId != null) && (postRecipientId.length() == 43)) {
+ post.setRecipient(core.getSone(postRecipientId));
+ }
+ posts.add(post);
} catch (NumberFormatException nfe1) {
/* TODO - mark Sone as bad. */
logger.log(Level.WARNING, "Downloaded post for Sone %s with invalid time: %s", new Object[] { sone, postTime });
}
}
- /* parse known Sones. */
- SimpleXML knownSonesXml = soneXml.getNode("known-sones");
- Set<Sone> knownSones = new HashSet<Sone>();
- if (knownSonesXml == null) {
- /* TODO - mark Sone as bad. */
- logger.log(Level.WARNING, "Downloaded Sone %s has no known Sones!", new Object[] { sone });
- } else {
- for (SimpleXML knownSoneXml : knownSonesXml.getNodes("known-sone")) {
- String knownSoneId = knownSoneXml.getValue("sone-id", null);
- String knownSoneKey = knownSoneXml.getValue("sone-key", null);
- String knownSoneName = knownSoneXml.getValue("sone-name", null);
- if ((knownSoneId == null) || (knownSoneKey == null) || (knownSoneName == null)) {
- /* TODO - mark Sone as bad. */
- logger.log(Level.WARNING, "Downloaded known Sone for Sone %s with missing data! ID: %s, Key: %s, Name: %s", new Object[] { sone, knownSoneId, knownSoneKey, knownSoneName });
- return null;
- }
- try {
- knownSones.add(core.getSone(knownSoneId).setRequestUri(new FreenetURI(knownSoneKey)).setName(knownSoneName));
- } catch (MalformedURLException mue1) {
- /* TODO - mark Sone as bad. */
- logger.log(Level.WARNING, "Downloaded known Sone for Sone %s with invalid key: %s", new Object[] { sone, knownSoneKey });
- return null;
- }
- }
- }
-
/* okay, apparently everything was parsed correctly. Now import. */
/* atomic setter operation on the Sone. */
synchronized (sone) {
sone.setPosts(posts);
sone.setReplies(replies);
sone.setLikePostIds(likedPostIds);
- sone.setModificationCounter(0);
+ sone.setLikeReplyIds(likedReplyIds);
}
- /* add all known Sones to core for downloading. */
- for (Sone knownSone : knownSones) {
- core.addSone(knownSone);
- }
return sone;
}