X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fsone%2Fcore%2FCore.java;h=1a1c6df5dfedc63fec66604c0866b85c3ddde3a8;hb=8e73d78985dbf9b12257bcd1408d17cef98394c6;hp=0f733b6e458a2f240e01df782990344675941639;hpb=21c4819261de874652e7c8be37bde5923758cf4b;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 0f733b6..1a1c6df 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,11 +32,15 @@ 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; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.sone.freenet.wot.WebOfTrustConnector; import net.pterodactylus.util.config.Configuration; import net.pterodactylus.util.config.ConfigurationException; import net.pterodactylus.util.filter.Filter; @@ -52,6 +57,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/4"); + /* Sone of Bombe. */ + defaultSones.add("USK@RuW~uAO35Ipne896-1OmaVJNPuYE4ZIB5oZ5ziaU57A,7rV3uiyztXBDt03DCoRiNwiGjgFCJuznM9Okc1opURU,AQACAAE/Sone/29"); + } + /** * Enumeration for the possible states of a {@link Sone}. * @@ -75,40 +90,46 @@ 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; /** Interface to freenet. */ private FreenetInterface freenetInterface; + /** The WoT connector. */ + private WebOfTrustConnector webOfTrustConnector; + /** The Sone downloader. */ private SoneDownloader soneDownloader; /** 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 = new HashMap(); + private final Map soneStatuses = Collections.synchronizedMap(new HashMap()); /* 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. */ public Core() { - super("Sone Core"); + super("Sone Core", false); } // @@ -116,6 +137,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 @@ -142,6 +172,27 @@ public class Core extends AbstractService { } /** + * Returns the Web of Trust connector. + * + * @return The Web of Trust connector + */ + public WebOfTrustConnector getWebOfTrustConnector() { + return webOfTrustConnector; + } + + /** + * Sets the Web of Trust connector. + * + * @param webOfTrustConnector + * The Web of Trust connector + * @return This core (for method chaining) + */ + public Core setWebOfTrustConnector(WebOfTrustConnector webOfTrustConnector) { + this.webOfTrustConnector = webOfTrustConnector; + return this; + } + + /** * Returns the local Sones. * * @return The local Sones @@ -173,7 +224,7 @@ public class Core extends AbstractService { * @return All known sones */ public Collection getKnownSones() { - return soneCache.values(); + return Collections.unmodifiableCollection(soneCache.values()); } /** @@ -182,14 +233,7 @@ public class Core extends AbstractService { * @return All remote Sones */ public Collection getRemoteSones() { - return Filters.filteredCollection(getKnownSones(), new Filter() { - - @Override - @SuppressWarnings("synthetic-access") - public boolean filterObject(Sone object) { - return !localSones.contains(object); - } - }); + return Collections.unmodifiableCollection(getKnownSones()); } /** @@ -322,7 +366,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 +458,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 +468,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 +528,8 @@ public class Core extends AbstractService { SoneInserter soneInserter = soneInserters.remove(sone); soneInserter.stop(); localSones.remove(sone); + soneStatuses.remove(sone); + soneCache.remove(sone.getId()); } /** @@ -522,6 +589,52 @@ public class Core extends AbstractService { return replies; } + /** + * Gets all Sones that like the given post. + * + * @param post + * The post to check for + * @return All Sones that like the post + */ + public Collection getLikes(final Post post) { + return Filters.filteredCollection(getKnownSones(), new Filter() { + + @Override + public boolean filterObject(Sone sone) { + return sone.isLikedPostId(post.getId()); + } + }); + } + + /** + * 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. + * + * @param reply + * The reply to remove + */ + public void deleteReply(Reply reply) { + reply.getSone().removeReply(reply); + replyCache.remove(reply.getId()); + } + // // SERVICE METHODS // @@ -552,11 +665,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; @@ -574,11 +737,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; @@ -622,15 +789,26 @@ public class Core extends AbstractService { sone.addFriend(friendSone); } - /* load blocked Sone IDs. */ - int blockedSoneCounter = 0; + /* load liked post IDs. */ + int likedPostIdCounter = 0; while (true) { - String blockedSonePrefix = sonePrefix + "/BlockedSone." + blockedSoneCounter++; - String blockedSoneId = configuration.getStringValue(blockedSonePrefix + "/ID").getValue(null); - if (blockedSoneId == null) { + String likedPostIdPrefix = sonePrefix + "/LikedPostId." + likedPostIdCounter++; + String likedPostId = configuration.getStringValue(likedPostIdPrefix + "/ID").getValue(null); + if (likedPostId == null) { break; } - sone.addBlockedSoneId(blockedSoneId); + sone.addLikedPostId(likedPostId); + } + + /* load liked reply IDs. */ + int likedReplyIdCounter = 0; + while (true) { + String likedReplyIdPrefix = sonePrefix + "/LikedReplyId." + likedReplyIdCounter++; + String likedReplyId = configuration.getStringValue(likedReplyIdPrefix + "/ID").getValue(null); + if (likedReplyId == null) { + break; + } + sone.addLikedReplyId(likedReplyId); } sone.setModificationCounter(modificationCounter); @@ -641,23 +819,6 @@ public class Core extends AbstractService { } while (true); logger.log(Level.INFO, "Loaded %d Sones.", getSones().size()); - /* load all known Sones. */ - int knownSonesCounter = 0; - while (true) { - String knownSonePrefix = "KnownSone." + knownSonesCounter++; - String knownSoneId = configuration.getStringValue(knownSonePrefix + "/ID").getValue(null); - if (knownSoneId == null) { - break; - } - String knownSoneName = configuration.getStringValue(knownSonePrefix + "/Name").getValue(null); - String knownSoneKey = configuration.getStringValue(knownSonePrefix + "/Key").getValue(null); - try { - getSone(knownSoneId).setName(knownSoneName).setRequestUri(new FreenetURI(knownSoneKey)); - } catch (MalformedURLException mue1) { - logger.log(Level.WARNING, "Could not create Sone from requestUri (“" + knownSoneKey + "”)!", mue1); - } - } - /* load all remote Sones. */ for (Sone remoteSone : getRemoteSones()) { loadSone(remoteSone); @@ -672,7 +833,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) { @@ -687,6 +854,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++; @@ -718,29 +888,26 @@ public class Core extends AbstractService { /* write null ID as terminator. */ configuration.getStringValue(sonePrefix + "/Friend." + friendId + "/ID").setValue(null); - /* write all blocked Sones. */ - int blockedSoneCounter = 0; - for (String blockedSoneId : sone.getBlockedSoneIds()) { - String blockedSonePrefix = sonePrefix + "/BlockedSone." + blockedSoneCounter++; - configuration.getStringValue(blockedSonePrefix + "/ID").setValue(blockedSoneId); + /* write all liked posts. */ + int likedPostIdCounter = 0; + for (String soneLikedPostId : sone.getLikedPostIds()) { + String likedPostIdPrefix = sonePrefix + "/LikedPostId." + likedPostIdCounter++; + configuration.getStringValue(likedPostIdPrefix + "/ID").setValue(soneLikedPostId); + } + configuration.getStringValue(sonePrefix + "/LikedPostId." + likedPostIdCounter + "/ID").setValue(null); + + /* write all liked replies. */ + int likedReplyIdCounter = 0; + for (String soneLikedReplyId : sone.getLikedReplyIds()) { + String likedReplyIdPrefix = sonePrefix + "/LikedReplyId." + likedReplyIdCounter++; + configuration.getStringValue(likedReplyIdPrefix + "/ID").setValue(soneLikedReplyId); } - configuration.getStringValue(sonePrefix + "/BlockedSone." + blockedSoneCounter + "/ID").setValue(null); + configuration.getStringValue(sonePrefix + "/LikedReplyId." + likedReplyIdCounter + "/ID").setValue(null); } /* write null ID as terminator. */ configuration.getStringValue("Sone/Sone." + soneId + "/ID").setValue(null); - /* write all known Sones. */ - int knownSonesCounter = 0; - for (Sone knownSone : getRemoteSones()) { - String knownSonePrefix = "KnownSone." + knownSonesCounter++; - configuration.getStringValue(knownSonePrefix + "/ID").setValue(knownSone.getId()); - configuration.getStringValue(knownSonePrefix + "/Name").setValue(knownSone.getName()); - configuration.getStringValue(knownSonePrefix + "/Key").setValue(knownSone.getRequestUri().toString()); - /* TODO - store all known stuff? */ - } - configuration.getStringValue("KnownSone." + knownSonesCounter + "/ID").setValue(null); - } catch (ConfigurationException ce1) { logger.log(Level.WARNING, "Could not store configuration!", ce1); }