X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fsone%2Fcore%2FCore.java;h=99ebc6d7356e9745389f5076c79eb0e12cd4f7b3;hb=df1e2e70c2f7031cd5b175d58b8f0b70c672176b;hp=8bf2cea3ab953520f775118ea564d91a6b7af3f9;hpb=3896f8c0877d4f935fce8a9c8e4109cfeb3e7203;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 8bf2cea..99ebc6d 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -17,6 +17,7 @@ package net.pterodactylus.sone.core; +import java.io.InputStream; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Collection; @@ -31,6 +32,9 @@ import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; +import net.pterodactylus.sone.core.Options.DefaultOption; +import net.pterodactylus.sone.core.Options.Option; +import net.pterodactylus.sone.core.Options.OptionWatcher; import net.pterodactylus.sone.core.SoneException.Type; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Profile; @@ -52,6 +56,16 @@ import freenet.keys.FreenetURI; */ public class Core extends AbstractService { + /** The default Sones. */ + private static final Set defaultSones = new HashSet(); + + static { + /* Sone of Sone. */ + defaultSones.add("USK@eRHt0ceFsHjRZ11j6dd68RSdIvfd8f9YjJLZ9lnhEyo,iJWjIWh6TkMZm1NY8qBranKTIuwsCPkVPG6T6c6ft-I,AQACAAE/Sone/3"); + /* Sone of Bombe. */ + defaultSones.add("USK@RuW~uAO35Ipne896-1OmaVJNPuYE4ZIB5oZ5ziaU57A,7rV3uiyztXBDt03DCoRiNwiGjgFCJuznM9Okc1opURU,AQACAAE/Sone/24"); + } + /** * Enumeration for the possible states of a {@link Sone}. * @@ -75,6 +89,9 @@ public class Core extends AbstractService { /** The logger. */ private static final Logger logger = Logging.getLogger(Core.class); + /** The options. */ + private final Options options = new Options(); + /** The configuration. */ private Configuration configuration; @@ -84,11 +101,14 @@ public class Core extends AbstractService { /** The Sone downloader. */ private SoneDownloader soneDownloader; + /** The Sone blacklist. */ + private final Set blacklistedSones = Collections.synchronizedSet(new HashSet()); + /** The local Sones. */ - private final Set localSones = new HashSet(); + private final Set localSones = Collections.synchronizedSet(new HashSet()); /** Sone inserters. */ - private final Map soneInserters = new HashMap(); + private final Map soneInserters = Collections.synchronizedMap(new HashMap()); /** The Sones’ statuses. */ private final Map soneStatuses = Collections.synchronizedMap(new HashMap()); @@ -96,13 +116,13 @@ public class Core extends AbstractService { /* various caches follow here. */ /** Cache for all known Sones. */ - private final Map soneCache = new HashMap(); + private final Map soneCache = Collections.synchronizedMap(new HashMap()); /** Cache for all known posts. */ - private final Map postCache = new HashMap(); + private final Map postCache = Collections.synchronizedMap(new HashMap()); /** Cache for all known replies. */ - private final Map replyCache = new HashMap(); + private final Map replyCache = Collections.synchronizedMap(new HashMap()); /** * Creates a new core. @@ -116,6 +136,15 @@ public class Core extends AbstractService { // /** + * Returns the options of the Sone plugin. + * + * @return The options of the Sone plugin + */ + public Options getOptions() { + return options; + } + + /** * Sets the configuration of the core. * * @param configuration @@ -147,7 +176,17 @@ public class Core extends AbstractService { * @return The local Sones */ public Set getSones() { - return Collections.unmodifiableSet(localSones); + return Filters.filteredSet(localSones, new Filter() { + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("synthetic-access") + public boolean filterObject(Sone sone) { + return !blacklistedSones.contains(sone); + } + }); } /** @@ -173,7 +212,17 @@ public class Core extends AbstractService { * @return All known sones */ public Collection getKnownSones() { - return soneCache.values(); + return Filters.filteredCollection(soneCache.values(), new Filter() { + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("synthetic-access") + public boolean filterObject(Sone sone) { + return !blacklistedSones.contains(sone); + } + }); } /** @@ -186,13 +235,33 @@ public class Core extends AbstractService { @Override @SuppressWarnings("synthetic-access") - public boolean filterObject(Sone object) { - return !localSones.contains(object); + public boolean filterObject(Sone sone) { + return !blacklistedSones.contains(sone) && !localSones.contains(sone); } }); } /** + * Returns all blacklisted Sones. + * + * @return All blacklisted Sones + */ + public Collection getBlacklistedSones() { + return Collections.unmodifiableCollection(blacklistedSones); + } + + /** + * Checks whether the given Sone is blacklisted. + * + * @param sone + * The Sone to check + * @return {@code true} if this Sone is blacklisted, {@code false} otherwise + */ + public boolean isBlacklistedSone(Sone sone) { + return blacklistedSones.contains(sone); + } + + /** * Returns the status of the given Sone. * * @param sone @@ -313,6 +382,38 @@ public class Core extends AbstractService { } /** + * Blackslists the given Sone. + * + * @param sone + * The Sone to blacklist + */ + public void blacklistSone(Sone sone) { + if (blacklistedSones.add(sone)) { + soneDownloader.removeSone(sone); + if (localSones.remove(sone)) { + SoneInserter soneInserter = soneInserters.remove(sone); + soneInserter.stop(); + } + } + } + + /** + * Unblacklists the given Sone. + * + * @param sone + * The Sone to unblacklist + */ + public void unblacklistSone(Sone sone) { + if (blacklistedSones.remove(sone)) { + if (sone.getInsertUri() != null) { + addLocalSone(sone); + } else { + addSone(sone); + } + } + } + + /** * Creates a new Sone at a random location. * * @param name @@ -322,7 +423,7 @@ public class Core extends AbstractService { * if a Sone error occurs */ public Sone createSone(String name) throws SoneException { - return createSone(name, "Sone-" + name, null, null); + return createSone(name, "Sone", null, null); } /** @@ -414,6 +515,7 @@ public class Core extends AbstractService { } else { addSone(parsedSone); } + setSoneStatus(parsedSone, SoneStatus.idle); } } catch (MalformedURLException mue1) { logger.log(Level.INFO, "Could not create URI from “" + requestUri + "”.", mue1); @@ -423,6 +525,26 @@ public class Core extends AbstractService { } /** + * Loads a Sone from an input stream. + * + * @param soneInputStream + * The input stream to load the Sone from + * @return The parsed Sone, or {@code null} if the Sone could not be parsed + */ + public Sone loadSone(InputStream soneInputStream) { + Sone parsedSone = soneDownloader.parseSone(soneInputStream); + if (parsedSone == null) { + return null; + } + if (parsedSone.getInsertUri() != null) { + addLocalSone(parsedSone); + } else { + addSone(parsedSone); + } + return parsedSone; + } + + /** * Loads and updates the given Sone. * * @param sone @@ -463,6 +585,8 @@ public class Core extends AbstractService { SoneInserter soneInserter = soneInserters.remove(sone); soneInserter.stop(); localSones.remove(sone); + soneStatuses.remove(sone); + soneCache.remove(sone.getId()); } /** @@ -529,8 +653,8 @@ public class Core extends AbstractService { * The post to check for * @return All Sones that like the post */ - public Set getLikes(final Post post) { - return Filters.filteredSet(getSones(), new Filter() { + public Collection getLikes(final Post post) { + return Filters.filteredCollection(getKnownSones(), new Filter() { @Override public boolean filterObject(Sone sone) { @@ -540,6 +664,23 @@ public class Core extends AbstractService { } /** + * Gets all Sones that like the given reply. + * + * @param reply + * The reply to check for + * @return All Sones that like the reply + */ + public Collection getLikes(final Reply reply) { + return Filters.filteredCollection(getKnownSones(), new Filter() { + + @Override + public boolean filterObject(Sone sone) { + return sone.isLikedReplyId(reply.getId()); + } + }); + } + + /** * Deletes the given reply. It is removed from its Sone and from the reply * cache. * @@ -581,11 +722,61 @@ public class Core extends AbstractService { // /** + * Adds some default Sones. + */ + private void addDefaultSones() { + for (String soneUri : defaultSones) { + loadSone(soneUri); + } + } + + /** * Loads the configuration. */ + @SuppressWarnings("unchecked") private void loadConfiguration() { logger.entering(Core.class.getName(), "loadConfiguration()"); + boolean firstStart = configuration.getBooleanValue("FirstStart").getValue(true); + if (firstStart) { + logger.log(Level.INFO, "First start of Sone, adding a couple of default Sones…"); + addDefaultSones(); + try { + configuration.getBooleanValue("FirstStart").setValue(false); + } catch (ConfigurationException ce1) { + logger.log(Level.WARNING, "Could not clear “first start” flag!"); + } + } + + options.addIntegerOption("InsertionDelay", new DefaultOption(60, new OptionWatcher() { + + @Override + public void optionChanged(Option option, Integer oldValue, Integer newValue) { + SoneInserter.setInsertionDelay(newValue); + } + + })); + + options.addBooleanOption("ClearOnNextRestart", new DefaultOption(false)); + options.addBooleanOption("ReallyClearOnNextRestart", new DefaultOption(false)); + + if (firstStart) { + return; + } + + options.getBooleanOption("ClearOnNextRestart").set(configuration.getBooleanValue("Option/ClearOnNextRestart").getValue(null)); + options.getBooleanOption("ReallyClearOnNextRestart").set(configuration.getBooleanValue("Option/ReallyClearOnNextRestart").getValue(null)); + boolean clearConfiguration = options.getBooleanOption("ClearOnNextRestart").get() && options.getBooleanOption("ReallyClearOnNextRestart").get(); + options.getBooleanOption("ClearOnNextRestart").set(null); + options.getBooleanOption("ReallyClearOnNextRestart").set(null); + if (clearConfiguration) { + /* stop loading the configuration. */ + addDefaultSones(); + return; + } + + options.getIntegerOption("InsertionDelay").set(configuration.getIntValue("Option/InsertionDelay").getValue(null)); + /* parse local Sones. */ logger.log(Level.INFO, "Loading Sones…"); int soneId = 0; @@ -603,11 +794,15 @@ public class Core extends AbstractService { String firstName = configuration.getStringValue(sonePrefix + "/Profile/FirstName").getValue(null); String middleName = configuration.getStringValue(sonePrefix + "/Profile/MiddleName").getValue(null); String lastName = configuration.getStringValue(sonePrefix + "/Profile/LastName").getValue(null); + Integer birthDay = configuration.getIntValue(sonePrefix + "/Profile/BirthDay").getValue(null); + Integer birthMonth = configuration.getIntValue(sonePrefix + "/Profile/BirthMonth").getValue(null); + Integer birthYear = configuration.getIntValue(sonePrefix + "/Profile/BirthYear").getValue(null); try { Profile profile = new Profile(); profile.setFirstName(firstName); profile.setMiddleName(middleName); profile.setLastName(lastName); + profile.setBirthDay(birthDay).setBirthMonth(birthMonth).setBirthYear(birthYear); Sone sone = getSone(id).setName(name).setTime(time).setRequestUri(new FreenetURI(requestUri)).setInsertUri(new FreenetURI(insertUri)); sone.setProfile(profile); int postId = 0; @@ -709,6 +904,24 @@ public class Core extends AbstractService { } } + /* load all blacklisted Sones. */ + int blacklistedSonesCounter = 0; + while (true) { + String blacklistedSonePrefix = "BlacklistedSone." + blacklistedSonesCounter++; + String blacklistedSoneId = configuration.getStringValue(blacklistedSonePrefix + "/ID").getValue(null); + if (blacklistedSoneId == null) { + break; + } + String blacklistedSoneName = configuration.getStringValue(blacklistedSonePrefix + "/Name").getValue(null); + String blacklistedSoneKey = configuration.getStringValue(blacklistedSonePrefix + "/Key").getValue(null); + String blacklistedSoneInsertKey = configuration.getStringValue(blacklistedSonePrefix + "/InsertKey").getValue(null); + try { + blacklistSone(getSone(blacklistedSoneId).setName(blacklistedSoneName).setRequestUri(new FreenetURI(blacklistedSoneKey)).setInsertUri((blacklistedSoneInsertKey != null) ? new FreenetURI(blacklistedSoneInsertKey) : null)); + } catch (MalformedURLException mue1) { + logger.log(Level.WARNING, "Could not create blacklisted Sone from requestUri (“" + blacklistedSoneKey + "”)!", mue1); + } + } + /* load all remote Sones. */ for (Sone remoteSone : getRemoteSones()) { loadSone(remoteSone); @@ -723,7 +936,13 @@ public class Core extends AbstractService { private void saveConfiguration() { Set sones = getSones(); logger.log(Level.INFO, "Storing %d Sones…", sones.size()); + try { + /* store the options first. */ + configuration.getIntValue("Option/InsertionDelay").setValue(options.getIntegerOption("InsertionDelay").getReal()); + configuration.getBooleanValue("Option/ClearOnNextRestart").setValue(options.getBooleanOption("ClearOnNextRestart").getReal()); + configuration.getBooleanValue("Option/ReallyClearOnNextRestart").setValue(options.getBooleanOption("ReallyClearOnNextRestart").getReal()); + /* store all Sones. */ int soneId = 0; for (Sone sone : localSones) { @@ -738,6 +957,9 @@ public class Core extends AbstractService { configuration.getStringValue(sonePrefix + "/Profile/FirstName").setValue(profile.getFirstName()); configuration.getStringValue(sonePrefix + "/Profile/MiddleName").setValue(profile.getMiddleName()); configuration.getStringValue(sonePrefix + "/Profile/LastName").setValue(profile.getLastName()); + configuration.getIntValue(sonePrefix + "/Profile/BirthDay").setValue(profile.getBirthDay()); + configuration.getIntValue(sonePrefix + "/Profile/BirthMonth").setValue(profile.getBirthMonth()); + configuration.getIntValue(sonePrefix + "/Profile/BirthYear").setValue(profile.getBirthYear()); int postId = 0; for (Post post : sone.getPosts()) { String postPrefix = sonePrefix + "/Post." + postId++; @@ -808,6 +1030,18 @@ public class Core extends AbstractService { } configuration.getStringValue("KnownSone." + knownSonesCounter + "/ID").setValue(null); + /* write all blacklisted Sones. */ + int blacklistedSonesCounter = 0; + for (Sone blacklistedSone : getBlacklistedSones()) { + String blacklistedSonePrefix = "BlacklistedSone." + blacklistedSonesCounter++; + configuration.getStringValue(blacklistedSonePrefix + "/ID").setValue(blacklistedSone.getId()); + configuration.getStringValue(blacklistedSonePrefix + "/Name").setValue(blacklistedSone.getName()); + configuration.getStringValue(blacklistedSonePrefix + "/Key").setValue(blacklistedSone.getRequestUri().toString()); + configuration.getStringValue(blacklistedSonePrefix + "/InsertKey").setValue((blacklistedSone.getInsertUri() != null) ? blacklistedSone.getInsertUri().toString() : null); + /* TODO - store all known stuff? */ + } + configuration.getStringValue("BlacklistedSone." + blacklistedSonesCounter + "/ID").setValue(null); + } catch (ConfigurationException ce1) { logger.log(Level.WARNING, "Could not store configuration!", ce1); }