X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fsone%2Fcore%2FCore.java;h=49140660e4ceea49531903f64dae79b27ea6218b;hb=8a43c22e3bfc31de0ae43209275f0311e2f875d5;hp=1860473c51599225a1cfebd5c7b446480cc14e3a;hpb=922af0c6ccb37071d1928d12e40aedd15511769a;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 1860473..4914066 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -25,6 +25,9 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.Map.Entry; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.logging.Logger; @@ -38,6 +41,7 @@ import net.pterodactylus.sone.data.Profile.Field; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.fcp.FcpInterface; +import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired; import net.pterodactylus.sone.freenet.wot.Identity; import net.pterodactylus.sone.freenet.wot.IdentityListener; import net.pterodactylus.sone.freenet.wot.IdentityManager; @@ -45,12 +49,15 @@ import net.pterodactylus.sone.freenet.wot.OwnIdentity; import net.pterodactylus.sone.freenet.wot.Trust; import net.pterodactylus.sone.freenet.wot.WebOfTrustException; import net.pterodactylus.sone.main.SonePlugin; +import net.pterodactylus.util.collection.Pair; 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.validation.IntegerRangeValidator; import net.pterodactylus.util.validation.Validation; import net.pterodactylus.util.version.Version; +import freenet.client.FetchResult; import freenet.keys.FreenetURI; /** @@ -107,6 +114,9 @@ public class Core implements IdentityListener, UpdateListener { /** The Sone downloader. */ private final SoneDownloader soneDownloader; + /** Sone downloader thread-pool. */ + private final ExecutorService soneDownloaders = Executors.newFixedThreadPool(10); + /** The update checker. */ private final UpdateChecker updateChecker; @@ -859,6 +869,14 @@ public class Core implements IdentityListener, UpdateListener { 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)); @@ -890,6 +908,9 @@ public class Core implements IdentityListener, UpdateListener { return null; } Sone sone = addLocalSone(ownIdentity); + sone.getOptions().addBooleanOption("AutoFollow", new DefaultOption(false)); + sone.addFriend("nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI"); + saveSone(sone); return sone; } @@ -922,6 +943,7 @@ public class Core implements IdentityListener, UpdateListener { for (Sone localSone : getLocalSones()) { if (localSone.getOptions().getBooleanOption("AutoFollow").get()) { localSone.addFriend(sone.getId()); + saveSone(localSone); } } } @@ -929,15 +951,15 @@ public class Core implements IdentityListener, UpdateListener { remoteSones.put(identity.getId(), sone); soneDownloader.addSone(sone); setSoneStatus(sone, SoneStatus.unknown); - new Thread(new Runnable() { + soneDownloaders.execute(new Runnable() { @Override @SuppressWarnings("synthetic-access") public void run() { - soneDownloader.fetchSone(sone); + soneDownloader.fetchSone(sone, sone.getRequestUri()); } - }, "Sone Downloader").start(); + }); return sone; } } @@ -1183,6 +1205,9 @@ public class Core implements IdentityListener, UpdateListener { return; } + /* initialize options. */ + sone.getOptions().addBooleanOption("AutoFollow", new DefaultOption(false)); + /* load Sone. */ String sonePrefix = "Sone/" + sone.getId(); Long soneTime = configuration.getLongValue(sonePrefix + "/Time").getValue(null); @@ -1283,7 +1308,6 @@ public class Core implements IdentityListener, UpdateListener { } /* load options. */ - sone.getOptions().addBooleanOption("AutoFollow", new DefaultOption(false)); sone.getOptions().getBooleanOption("AutoFollow").set(configuration.getBooleanValue(sonePrefix + "/Options/AutoFollow").getValue(null)); /* if we’re still here, Sone was loaded successfully. */ @@ -1507,6 +1531,7 @@ public class Core implements IdentityListener, UpdateListener { synchronized (posts) { posts.remove(post.getId()); } + coreListenerManager.firePostRemoved(post); synchronized (newPosts) { markPostKnown(post); knownPosts.remove(post.getId()); @@ -1703,11 +1728,12 @@ 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.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()); configuration.getStringValue("Option/TrustComment").setValue(options.getStringOption("TrustComment").getReal()); configuration.getBooleanValue("Option/ActivateFcpInterface").setValue(options.getBooleanOption("ActivateFcpInterface").getReal()); - configuration.getBooleanValue("Option/FcpWriteFromFullAccessOnly").setValue(options.getBooleanOption("FcpWriteFromFullAccessOnly").getReal()); + configuration.getIntValue("Option/FcpFullAccessRequired").setValue(options.getIntegerOption("FcpFullAccessRequired").getReal()); configuration.getBooleanValue("Option/SoneRescueMode").setValue(options.getBooleanOption("SoneRescueMode").getReal()); configuration.getBooleanValue("Option/ClearOnNextRestart").setValue(options.getBooleanOption("ClearOnNextRestart").getReal()); configuration.getBooleanValue("Option/ReallyClearOnNextRestart").setValue(options.getBooleanOption("ReallyClearOnNextRestart").getReal()); @@ -1770,7 +1796,7 @@ public class Core implements IdentityListener, UpdateListener { @SuppressWarnings("unchecked") private void loadConfiguration() { /* create options. */ - options.addIntegerOption("InsertionDelay", new DefaultOption(60, new OptionWatcher() { + options.addIntegerOption("InsertionDelay", new DefaultOption(60, new IntegerRangeValidator(0, Integer.MAX_VALUE), new OptionWatcher() { @Override public void optionChanged(Option option, Integer oldValue, Integer newValue) { @@ -1778,9 +1804,10 @@ public class Core implements IdentityListener, UpdateListener { } })); - options.addIntegerOption("PostsPerPage", new DefaultOption(25)); - options.addIntegerOption("PositiveTrust", new DefaultOption(75)); - options.addIntegerOption("NegativeTrust", new DefaultOption(-25)); + options.addIntegerOption("PostsPerPage", new DefaultOption(10, new IntegerRangeValidator(1, Integer.MAX_VALUE))); + 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))); options.addStringOption("TrustComment", new DefaultOption("Set from Sone Web Interface")); options.addBooleanOption("ActivateFcpInterface", new DefaultOption(false, new OptionWatcher() { @@ -1790,12 +1817,12 @@ public class Core implements IdentityListener, UpdateListener { fcpInterface.setActive(newValue); } })); - options.addBooleanOption("FcpWriteFromFullAccessOnly", new DefaultOption(true, new OptionWatcher() { + options.addIntegerOption("FcpFullAccessRequired", new DefaultOption(2, new OptionWatcher() { @Override @SuppressWarnings("synthetic-access") - public void optionChanged(Option option, Boolean oldValue, Boolean newValue) { - fcpInterface.setAllowWriteFromFullAccessOnly(newValue); + public void optionChanged(Option option, Integer oldValue, Integer newValue) { + fcpInterface.setFullAccessRequired(FullAccessRequired.values()[newValue]); } })); @@ -1814,13 +1841,14 @@ public class Core implements IdentityListener, UpdateListener { return; } - options.getIntegerOption("InsertionDelay").set(configuration.getIntValue("Option/InsertionDelay").getValue(null)); - options.getIntegerOption("PostsPerPage").set(configuration.getIntValue("Option/PostsPerPage").getValue(null)); - options.getIntegerOption("PositiveTrust").set(configuration.getIntValue("Option/PositiveTrust").getValue(null)); - options.getIntegerOption("NegativeTrust").set(configuration.getIntValue("Option/NegativeTrust").getValue(null)); + loadConfigurationValue("InsertionDelay"); + loadConfigurationValue("PostsPerPage"); + options.getBooleanOption("RequireFullAccess").set(configuration.getBooleanValue("Option/RequireFullAccess").getValue(null)); + loadConfigurationValue("PositiveTrust"); + loadConfigurationValue("NegativeTrust"); options.getStringOption("TrustComment").set(configuration.getStringValue("Option/TrustComment").getValue(null)); options.getBooleanOption("ActivateFcpInterface").set(configuration.getBooleanValue("Option/ActivateFcpInterface").getValue(null)); - options.getBooleanOption("FcpWriteFromFullAccessOnly").set(configuration.getBooleanValue("Option/FcpWriteFromFullAccessOnly").getValue(null)); + options.getIntegerOption("FcpFullAccessRequired").set(configuration.getIntValue("Option/FcpFullAccessRequired").getValue(null)); options.getBooleanOption("SoneRescueMode").set(configuration.getBooleanValue("Option/SoneRescueMode").getValue(null)); /* load known Sones. */ @@ -1874,6 +1902,21 @@ public class Core implements IdentityListener, UpdateListener { } /** + * Loads an {@link Integer} configuration value for the option with the + * given name, logging validation failures. + * + * @param optionName + * The name of the option to load + */ + private void loadConfigurationValue(String optionName) { + try { + options.getIntegerOption(optionName).set(configuration.getIntValue("Option/" + optionName).getValue(null)); + } catch (IllegalArgumentException iae1) { + logger.log(Level.WARNING, "Invalid value for " + optionName + " in configuration, using default."); + } + } + + /** * Generate a Sone URI from the given URI and latest edition. * * @param uriString @@ -1937,6 +1980,7 @@ public class Core implements IdentityListener, UpdateListener { public void run() { Sone sone = getRemoteSone(identity.getId()); sone.setIdentity(identity); + sone.setLatestEdition(Numbers.safeParseLong(identity.getProperty("Sone.LatestEdition"), sone.getLatestEdition())); soneDownloader.addSone(sone); soneDownloader.fetchSone(sone); } @@ -1949,6 +1993,48 @@ public class Core implements IdentityListener, UpdateListener { @Override public void identityRemoved(OwnIdentity ownIdentity, Identity identity) { trustedIdentities.get(ownIdentity).remove(identity); + boolean foundIdentity = false; + for (Entry> trustedIdentity : trustedIdentities.entrySet()) { + if (trustedIdentity.getKey().equals(ownIdentity)) { + continue; + } + if (trustedIdentity.getValue().contains(identity)) { + foundIdentity = true; + } + } + if (foundIdentity) { + /* some local identity still trusts this identity, don’t remove. */ + return; + } + Sone sone = getSone(identity.getId(), false); + if (sone == null) { + /* TODO - we don’t have the Sone anymore. should this happen? */ + return; + } + synchronized (posts) { + synchronized (newPosts) { + for (Post post : sone.getPosts()) { + posts.remove(post.getId()); + newPosts.remove(post.getId()); + coreListenerManager.firePostRemoved(post); + } + } + } + synchronized (replies) { + synchronized (newReplies) { + for (Reply reply : sone.getReplies()) { + replies.remove(reply.getId()); + newReplies.remove(reply.getId()); + coreListenerManager.fireReplyRemoved(reply); + } + } + } + synchronized (remoteSones) { + remoteSones.remove(identity.getId()); + } + synchronized (newSones) { + newSones.remove(identity.getId()); + } } // @@ -1994,6 +2080,18 @@ public class Core implements IdentityListener, UpdateListener { } /** + * Validates the given insertion delay. + * + * @param insertionDelay + * The insertion delay to validate + * @return {@code true} if the given insertion delay was valid, {@code + * false} otherwise + */ + public boolean validateInsertionDelay(Integer insertionDelay) { + return options.getIntegerOption("InsertionDelay").validate(insertionDelay); + } + + /** * Sets the insertion delay * * @param insertionDelay @@ -2016,6 +2114,18 @@ public class Core implements IdentityListener, UpdateListener { } /** + * Validates the number of posts per page. + * + * @param postsPerPage + * The number of posts per page + * @return {@code true} if the number of posts per page was valid, + * {@code false} otherwise + */ + public boolean validatePostsPerPage(Integer postsPerPage) { + return options.getIntegerOption("PostsPerPage").validate(postsPerPage); + } + + /** * Sets the number of posts to show per page. * * @param postsPerPage @@ -2028,6 +2138,27 @@ public class Core implements IdentityListener, UpdateListener { } /** + * Returns whether Sone requires full access to be even visible. + * + * @return {@code true} if Sone requires full access, {@code false} + * otherwise + */ + public boolean isRequireFullAccess() { + return options.getBooleanOption("RequireFullAccess").get(); + } + + /** + * Sets whether Sone requires full access to be even visible. + * + * @param requireFullAccess + * {@code true} if Sone requires full access, {@code false} + * otherwise + */ + public void setRequireFullAccess(Boolean requireFullAccess) { + options.getBooleanOption("RequireFullAccess").set(requireFullAccess); + } + + /** * Returns the positive trust. * * @return The positive trust @@ -2037,6 +2168,18 @@ public class Core implements IdentityListener, UpdateListener { } /** + * Validates the positive trust. + * + * @param positiveTrust + * The positive trust to validate + * @return {@code true} if the positive trust was valid, {@code false} + * otherwise + */ + public boolean validatePositiveTrust(Integer positiveTrust) { + return options.getIntegerOption("PositiveTrust").validate(positiveTrust); + } + + /** * Sets the positive trust. * * @param positiveTrust @@ -2059,6 +2202,18 @@ public class Core implements IdentityListener, UpdateListener { } /** + * Validates the negative trust. + * + * @param negativeTrust + * The negative trust to validate + * @return {@code true} if the negative trust was valid, {@code false} + * otherwise + */ + public boolean validateNegativeTrust(Integer negativeTrust) { + return options.getIntegerOption("NegativeTrust").validate(negativeTrust); + } + + /** * Sets the negative trust. * * @param negativeTrust @@ -2122,29 +2277,26 @@ public class Core implements IdentityListener, UpdateListener { } /** - * Returns whether write access to the FCP interface is only allowed - * from the allowed FCP hosts of the node configuration. + * Returns the action level for which full access to the FCP interface + * is required. * - * @return {@code true} if only allowed hosts are allowed to change data - * using the FCP interface, {@code false} if everybody can - * change data using the FCP interface + * @return The action level for which full access to the FCP interface + * is required */ - public boolean isFcpWriteFromFullAccessOnly() { - return options.getBooleanOption("FcpWriteFromFullAccessOnly").get(); + public FullAccessRequired getFcpFullAccessRequired() { + return FullAccessRequired.values()[options.getIntegerOption("FcpFullAccessRequired").get()]; } /** - * Sets whether write access to the FCP interface is only allowed from - * the allowed FCP hosts of the node configuration. + * Sets the action level for which full access to the FCP interface is + * required * - * @param fcpWriteFromFullAccessOnly - * {@code true} if only allowed hosts should be allowed to - * change data using the FCP interface, {@code false} if - * everybody can change data using the FCP interface - * @return This preferences object + * @param fcpFullAccessRequired + * The action level + * @return This preferences */ - public Preferences setFcpWriteFromFullAccessOnly(boolean fcpWriteFromFullAccessOnly) { - options.getBooleanOption("FcpWriteFromFullAccessOnly").set(fcpWriteFromFullAccessOnly); + public Preferences setFcpFullAccessRequired(FullAccessRequired fcpFullAccessRequired) { + options.getIntegerOption("FcpFullAccessRequired").set((fcpFullAccessRequired != null) ? fcpFullAccessRequired.ordinal() : null); return this; }