X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fsone%2Fcore%2FCore.java;h=ea36aad76bf88c22ff6376495271d050c5133f61;hb=bb2c8cb2d47a77bcef2d299ad4bf8e16f22a6198;hp=c480d9b8f758017a2311424b58557ee36298f0c1;hpb=57b65838f44ffc65a97aefbbec3e69b576cea7cd;p=Sone.git diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index c480d9b..ea36aad 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -53,7 +53,10 @@ import net.pterodactylus.util.config.Configuration; import net.pterodactylus.util.config.ConfigurationException; import net.pterodactylus.util.logging.Logging; import net.pterodactylus.util.number.Numbers; +import net.pterodactylus.util.thread.Ticker; +import net.pterodactylus.util.validation.EqualityValidator; import net.pterodactylus.util.validation.IntegerRangeValidator; +import net.pterodactylus.util.validation.OrValidator; import net.pterodactylus.util.validation.Validation; import net.pterodactylus.util.version.Version; import freenet.keys.FreenetURI; @@ -63,7 +66,7 @@ import freenet.keys.FreenetURI; * * @author David ‘Bombe’ Roden */ -public class Core implements IdentityListener, UpdateListener { +public class Core implements IdentityListener, UpdateListener, SoneProvider, PostProvider { /** * Enumeration for the possible states of a {@link Sone}. @@ -122,6 +125,7 @@ public class Core implements IdentityListener, UpdateListener { private volatile FcpInterface fcpInterface; /** Whether the core has been stopped. */ + @SuppressWarnings("unused") private volatile boolean stopped; /** The Sones’ statuses. */ @@ -136,6 +140,10 @@ public class Core implements IdentityListener, UpdateListener { /* synchronize access on this on localSones. */ private final Map soneInserters = new HashMap(); + /** Sone rescuers. */ + /* synchronize access on this on localSones. */ + private final Map soneRescuers = new HashMap(); + /** All local Sones. */ /* synchronize access on this on itself. */ private Map localSones = new HashMap(); @@ -177,6 +185,9 @@ public class Core implements IdentityListener, UpdateListener { /** Trusted identities, sorted by own identities. */ private Map> trustedIdentities = Collections.synchronizedMap(new HashMap>()); + /** Ticker for threads that mark own elements as known. */ + private Ticker localElementTicker = new Ticker(); + /** * Creates a new core. * @@ -300,6 +311,26 @@ public class Core implements IdentityListener, UpdateListener { } /** + * Returns the Sone rescuer for the given local Sone. + * + * @param sone + * The local Sone to get the rescuer for + * @return The Sone rescuer for the given Sone + */ + public SoneRescuer getSoneRescuer(Sone sone) { + Validation.begin().isNotNull("Sone", sone).check().is("Local Sone", isLocalSone(sone)).check(); + synchronized (localSones) { + SoneRescuer soneRescuer = soneRescuers.get(sone); + if (soneRescuer == null) { + soneRescuer = new SoneRescuer(this, soneDownloader, sone); + soneRescuers.put(sone, soneRescuer); + soneRescuer.start(); + } + return soneRescuer; + } + } + + /** * Returns whether the given Sone is currently locked. * * @param sone @@ -350,6 +381,7 @@ public class Core implements IdentityListener, UpdateListener { * @return The Sone with the given ID, or {@code null} if there is no such * Sone */ + @Override public Sone getSone(String id, boolean create) { if (isLocalSone(id)) { return getLocalSone(id); @@ -572,6 +604,7 @@ public class Core implements IdentityListener, UpdateListener { * exists, {@code false} to return {@code null} * @return The post, or {@code null} if there is no such post */ + @Override public Post getPost(String postId, boolean create) { synchronized (posts) { Post post = posts.get(postId); @@ -852,41 +885,7 @@ public class Core implements IdentityListener, UpdateListener { soneInserters.put(sone, soneInserter); setSoneStatus(sone, SoneStatus.idle); loadSone(sone); - if (!preferences.isSoneRescueMode()) { - soneInserter.start(); - } - new Thread(new Runnable() { - - @Override - @SuppressWarnings("synthetic-access") - public void run() { - if (!preferences.isSoneRescueMode()) { - return; - } - logger.log(Level.INFO, "Trying to restore Sone from Freenet…"); - coreListenerManager.fireRescuingSone(sone); - lockSone(sone); - long edition = sone.getLatestEdition(); - /* find the latest edition the node knows about. */ - Pair currentUri = freenetInterface.fetchUri(sone.getRequestUri()); - if (currentUri != null) { - long currentEdition = currentUri.getLeft().getEdition(); - if (currentEdition > edition) { - edition = currentEdition; - } - } - while (!stopped && (edition >= 0) && preferences.isSoneRescueMode()) { - logger.log(Level.FINE, "Downloading edition " + edition + "…"); - soneDownloader.fetchSone(sone, sone.getRequestUri().setKeyType("SSK").setDocName("Sone-" + edition)); - --edition; - } - logger.log(Level.INFO, "Finished restoring Sone from Freenet, starting Inserter…"); - saveSone(sone); - coreListenerManager.fireRescuedSone(sone); - soneInserter.start(); - } - - }, "Sone Downloader").start(); + soneInserter.start(); return sone; } } @@ -1054,14 +1053,28 @@ public class Core implements IdentityListener, UpdateListener { } /** - * Updates the stores Sone with the given Sone. + * Updates the stored Sone with the given Sone. * * @param sone * The updated Sone */ public void updateSone(Sone sone) { + updateSone(sone, false); + } + + /** + * Updates the stored Sone with the given Sone. If {@code soneRescueMode} is + * {@code true}, an older Sone than the current Sone can be given to restore + * an old state. + * + * @param sone + * The Sone to update + * @param soneRescueMode + * {@code true} if the stored Sone should be updated regardless + * of the age of the given Sone + */ + public void updateSone(Sone sone, boolean soneRescueMode) { if (hasSone(sone.getId())) { - boolean soneRescueMode = isLocalSone(sone) && preferences.isSoneRescueMode(); Sone storedSone = getSone(sone.getId()); if (!soneRescueMode && !(sone.getTime() > storedSone.getTime())) { logger.log(Level.FINE, "Downloaded Sone %s is not newer than stored Sone %s.", new Object[] { sone, storedSone }); @@ -1498,7 +1511,7 @@ public class Core implements IdentityListener, UpdateListener { logger.log(Level.FINE, "Tried to create post for non-local Sone: %s", sone); return null; } - Post post = new Post(sone, time, text); + final Post post = new Post(sone, time, text); if (recipient != null) { post.setRecipient(recipient); } @@ -1511,6 +1524,16 @@ public class Core implements IdentityListener, UpdateListener { } sone.addPost(post); saveSone(sone); + localElementTicker.registerEvent(System.currentTimeMillis() + 10 * 1000, new Runnable() { + + /** + * {@inheritDoc} + */ + @Override + public void run() { + markPostKnown(post); + } + }, "Mark " + post + " read."); return post; } @@ -1631,7 +1654,7 @@ public class Core implements IdentityListener, UpdateListener { logger.log(Level.FINE, "Tried to create reply for non-local Sone: %s", sone); return null; } - Reply reply = new Reply(sone, post, System.currentTimeMillis(), text); + final Reply reply = new Reply(sone, post, System.currentTimeMillis(), text); synchronized (replies) { replies.put(reply.getId(), reply); } @@ -1641,6 +1664,16 @@ public class Core implements IdentityListener, UpdateListener { } sone.addReply(reply); saveSone(sone); + localElementTicker.registerEvent(System.currentTimeMillis() + 10 * 1000, new Runnable() { + + /** + * {@inheritDoc} + */ + @Override + public void run() { + markReplyKnown(reply); + } + }, "Mark " + reply + " read."); return reply; } @@ -1701,6 +1734,9 @@ public class Core implements IdentityListener, UpdateListener { for (SoneInserter soneInserter : soneInserters.values()) { soneInserter.stop(); } + for (Sone localSone : localSones.values()) { + saveSone(localSone); + } } updateChecker.stop(); updateChecker.removeUpdateListener(this); @@ -1726,6 +1762,7 @@ public class Core implements IdentityListener, UpdateListener { configuration.getIntValue("Option/ConfigurationVersion").setValue(0); configuration.getIntValue("Option/InsertionDelay").setValue(options.getIntegerOption("InsertionDelay").getReal()); configuration.getIntValue("Option/PostsPerPage").setValue(options.getIntegerOption("PostsPerPage").getReal()); + configuration.getIntValue("Option/CharactersPerPost").setValue(options.getIntegerOption("CharactersPerPost").getReal()); configuration.getBooleanValue("Option/RequireFullAccess").setValue(options.getBooleanOption("RequireFullAccess").getReal()); configuration.getIntValue("Option/PositiveTrust").setValue(options.getIntegerOption("PositiveTrust").getReal()); configuration.getIntValue("Option/NegativeTrust").setValue(options.getIntegerOption("NegativeTrust").getReal()); @@ -1803,6 +1840,7 @@ public class Core implements IdentityListener, UpdateListener { })); options.addIntegerOption("PostsPerPage", new DefaultOption(10, new IntegerRangeValidator(1, Integer.MAX_VALUE))); + options.addIntegerOption("CharactersPerPost", new DefaultOption(200, new OrValidator(new IntegerRangeValidator(50, Integer.MAX_VALUE), new EqualityValidator(-1)))); options.addBooleanOption("RequireFullAccess", new DefaultOption(false)); options.addIntegerOption("PositiveTrust", new DefaultOption(75, new IntegerRangeValidator(0, 100))); options.addIntegerOption("NegativeTrust", new DefaultOption(-25, new IntegerRangeValidator(-100, 100))); @@ -1841,6 +1879,7 @@ public class Core implements IdentityListener, UpdateListener { loadConfigurationValue("InsertionDelay"); loadConfigurationValue("PostsPerPage"); + loadConfigurationValue("CharactersPerPost"); options.getBooleanOption("RequireFullAccess").set(configuration.getBooleanValue("Option/RequireFullAccess").getValue(null)); loadConfigurationValue("PositiveTrust"); loadConfigurationValue("NegativeTrust"); @@ -2032,6 +2071,7 @@ public class Core implements IdentityListener, UpdateListener { } synchronized (newSones) { newSones.remove(identity.getId()); + coreListenerManager.fireSoneRemoved(sone); } } @@ -2136,6 +2176,41 @@ public class Core implements IdentityListener, UpdateListener { } /** + * Returns the number of characters per post, or -1 if the + * posts should not be cut off. + * + * @return The numbers of characters per post + */ + public int getCharactersPerPost() { + return options.getIntegerOption("CharactersPerPost").get(); + } + + /** + * Validates the number of characters per post. + * + * @param charactersPerPost + * The number of characters per post + * @return {@code true} if the number of characters per post was valid, + * {@code false} otherwise + */ + public boolean validateCharactersPerPost(Integer charactersPerPost) { + return options.getIntegerOption("CharactersPerPost").validate(charactersPerPost); + } + + /** + * Sets the number of characters per post. + * + * @param charactersPerPost + * The number of characters per post, or -1 to + * not cut off the posts + * @return This preferences objects + */ + public Preferences setCharactersPerPost(Integer charactersPerPost) { + options.getIntegerOption("CharactersPerPost").set(charactersPerPost); + return this; + } + + /** * Returns whether Sone requires full access to be even visible. * * @return {@code true} if Sone requires full access, {@code false} @@ -2299,29 +2374,6 @@ public class Core implements IdentityListener, UpdateListener { } /** - * Returns whether the rescue mode is active. - * - * @return {@code true} if the rescue mode is active, {@code false} - * otherwise - */ - public boolean isSoneRescueMode() { - return options.getBooleanOption("SoneRescueMode").get(); - } - - /** - * Sets whether the rescue mode is active. - * - * @param soneRescueMode - * {@code true} if the rescue mode is active, {@code false} - * otherwise - * @return This preferences - */ - public Preferences setSoneRescueMode(Boolean soneRescueMode) { - options.getBooleanOption("SoneRescueMode").set(soneRescueMode); - return this; - } - - /** * Returns whether Sone should clear its settings on the next restart. * In order to be effective, {@link #isReallyClearOnNextRestart()} needs * to return {@code true} as well!