X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fsone%2Fcore%2FCore.java;h=e46eceb159d07cc800ba52573d2258e1a44e7d18;hp=43561204030924d16aba23c63b154bcff1fe9347;hb=ac3e2838d8b99eb66c26030afe50731f536bd17b;hpb=fd560d013c7de7b8c70b65156a41d4a6bc9aeb06 diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index 4356120..e46eceb 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -59,6 +59,8 @@ import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.PostBuilder; import net.pterodactylus.sone.data.PostBuilderFactory; import net.pterodactylus.sone.data.PostReply; +import net.pterodactylus.sone.data.PostReplyBuilder; +import net.pterodactylus.sone.data.PostReplyBuilderFactory; import net.pterodactylus.sone.data.Profile; import net.pterodactylus.sone.data.Profile.Field; import net.pterodactylus.sone.data.Reply; @@ -66,7 +68,6 @@ import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.data.Sone.ShowCustomAvatars; import net.pterodactylus.sone.data.Sone.SoneStatus; import net.pterodactylus.sone.data.TemporaryImage; -import net.pterodactylus.sone.data.impl.PostReplyImpl; import net.pterodactylus.sone.fcp.FcpInterface; import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired; import net.pterodactylus.sone.freenet.wot.Identity; @@ -87,6 +88,7 @@ import net.pterodactylus.util.service.AbstractService; import net.pterodactylus.util.thread.NamedThreadFactory; import com.google.common.base.Function; +import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Collections2; @@ -103,7 +105,7 @@ import freenet.keys.FreenetURI; * * @author David ‘Bombe’ Roden */ -public class Core extends AbstractService implements SoneProvider, PostProvider { +public class Core extends AbstractService implements SoneProvider, PostProvider, PostReplyProvider { /** The logger. */ private static final Logger logger = Logging.getLogger(Core.class); @@ -151,7 +153,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider private volatile FcpInterface fcpInterface; /** The times Sones were followed. */ - private final Map soneFollowingTimes = new HashMap(); + private final Map soneFollowingTimes = new HashMap(); /** Locked local Sones. */ /* synchronize on itself. */ @@ -181,6 +183,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider /** All known posts. */ private final Set knownPosts = new HashSet(); + /** The post reply builder factory. */ + private final PostReplyBuilderFactory postReplyBuilderFactory; + /** All replies. */ private final Map replies = new HashMap(); @@ -224,9 +229,11 @@ public class Core extends AbstractService implements SoneProvider, PostProvider * The event bus * @param postBuilderFactory * The post builder + * @param postReplyBuilderFactory + * The post reply builder factory */ @Inject - public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, WebOfTrustUpdater webOfTrustUpdater, EventBus eventBus, PostBuilderFactory postBuilderFactory) { + public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, WebOfTrustUpdater webOfTrustUpdater, EventBus eventBus, PostBuilderFactory postBuilderFactory, PostReplyBuilderFactory postReplyBuilderFactory) { super("Sone Core"); this.configuration = configuration; this.freenetInterface = freenetInterface; @@ -237,6 +244,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider this.webOfTrustUpdater = webOfTrustUpdater; this.eventBus = eventBus; this.postBuilderFactory = postBuilderFactory; + this.postReplyBuilderFactory = postReplyBuilderFactory; } // @@ -497,10 +505,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider */ public long getSoneFollowingTime(Sone sone) { synchronized (soneFollowingTimes) { - if (soneFollowingTimes.containsKey(sone)) { - return soneFollowingTimes.get(sone); - } - return Long.MAX_VALUE; + return Optional.fromNullable(soneFollowingTimes.get(sone.getId())).or(Long.MAX_VALUE); } } @@ -533,9 +538,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider * {@inheritDoc} */ @Override - public Post getPost(String postId) { + public Optional getPost(String postId) { synchronized (posts) { - return posts.get(postId); + return Optional.fromNullable(posts.get(postId)); } } @@ -561,35 +566,28 @@ public class Core extends AbstractService implements SoneProvider, PostProvider } /** - * Returns the reply with the given ID. If there is no reply with the given - * ID yet, a new one is created, unless {@code create} is false in which - * case {@code null} is returned. + * Returns a post reply builder. * - * @param replyId - * The ID of the reply to get - * @param create - * {@code true} to always return a {@link Reply}, {@code false} - * to return {@code null} if no reply can be found - * @return The reply, or {@code null} if there is no such reply + * @return A new post reply builder */ - public PostReply getPostReply(String replyId, boolean create) { + public PostReplyBuilder postReplyBuilder() { + return postReplyBuilderFactory.newPostReplyBuilder(); + } + + /** + * {@inheritDoc} + */ + @Override + public Optional getPostReply(String replyId) { synchronized (replies) { - PostReply reply = replies.get(replyId); - if (create && (reply == null)) { - reply = new PostReplyImpl(replyId); - replies.put(replyId, reply); - } - return reply; + return Optional.fromNullable(replies.get(replyId)); } } /** - * Returns all replies for the given post, order ascending by time. - * - * @param post - * The post to get all replies for - * @return All replies for the given post + * {@inheritDoc} */ + @Override public List getReplies(final Post post) { return Ordering.from(Reply.TIME_COMPARATOR).sortedCopy(FluentIterable.from(getSones()).transformAndConcat(new Function>() { @@ -601,7 +599,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider @Override public boolean apply(PostReply reply) { - return post.equals(reply.getPost()); + return post.getId().equals(reply.getPostId()); } })); } @@ -675,9 +673,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider Set posts = new HashSet(); synchronized (bookmarkedPosts) { for (String bookmarkedPostId : bookmarkedPosts) { - Post post = getPost(bookmarkedPostId); - if (post != null) { - posts.add(post); + Optional post = getPost(bookmarkedPostId); + if (!post.isPresent()) { + posts.add(post.get()); } } } @@ -856,7 +854,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider sone.getOptions().addBooleanOption("ShowNotification/NewReplies", new DefaultOption(true)); sone.getOptions().addEnumOption("ShowCustomAvatars", new DefaultOption(ShowCustomAvatars.NEVER)); - followSone(sone, getSone("nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI")); + followSone(sone, "nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI"); touchConfiguration(); return sone; } @@ -876,7 +874,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider synchronized (sones) { final Sone sone = getRemoteSone(identity.getId(), true).setIdentity(identity); boolean newSone = sone.getRequestUri() == null; - sone.setRequestUri(getSoneUri(identity.getRequestUri())); + sone.setRequestUri(SoneUri.create(identity.getRequestUri())); sone.setLatestEdition(Numbers.safeParseLong(identity.getProperty("Sone.LatestEdition"), (long) 0)); if (newSone) { synchronized (knownSones) { @@ -887,7 +885,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider eventBus.post(new NewSoneFoundEvent(sone)); for (Sone localSone : getLocalSones()) { if (localSone.getOptions().getBooleanOption("AutoFollow").get()) { - followSone(localSone, sone); + followSone(localSone, sone.getId()); } } } @@ -917,33 +915,15 @@ public class Core extends AbstractService implements SoneProvider, PostProvider public void followSone(Sone sone, String soneId) { checkNotNull(sone, "sone must not be null"); checkNotNull(soneId, "soneId must not be null"); - Sone followedSone = getSone(soneId, true); - if (followedSone == null) { - logger.log(Level.INFO, String.format("Ignored Sone with invalid ID: %s", soneId)); - return; - } - followSone(sone, getSone(soneId)); - } - - /** - * Lets the given local Sone follow the other given Sone. If the given Sone - * was not followed by any local Sone before, this will mark all elements of - * the followed Sone as read that have been created before the current - * moment. - * - * @param sone - * The local Sone that should follow the other Sone - * @param followedSone - * The Sone that should be followed - */ - public void followSone(Sone sone, Sone followedSone) { - checkNotNull(sone, "sone must not be null"); - checkNotNull(followedSone, "followedSone must not be null"); - sone.addFriend(followedSone.getId()); + sone.addFriend(soneId); synchronized (soneFollowingTimes) { - if (!soneFollowingTimes.containsKey(followedSone)) { + if (!soneFollowingTimes.containsKey(soneId)) { long now = System.currentTimeMillis(); - soneFollowingTimes.put(followedSone, now); + soneFollowingTimes.put(soneId, now); + Sone followedSone = getSone(soneId); + if (followedSone == null) { + return; + } for (Post post : followedSone.getPosts()) { if (post.getTime() < now) { markPostKnown(post); @@ -970,30 +950,14 @@ public class Core extends AbstractService implements SoneProvider, PostProvider public void unfollowSone(Sone sone, String soneId) { checkNotNull(sone, "sone must not be null"); checkNotNull(soneId, "soneId must not be null"); - unfollowSone(sone, getSone(soneId, false)); - } - - /** - * Lets the given local Sone unfollow the other given Sone. If the given - * local Sone is the last local Sone that followed the given Sone, its - * following time will be removed. - * - * @param sone - * The local Sone that should unfollow another Sone - * @param unfollowedSone - * The Sone being unfollowed - */ - public void unfollowSone(Sone sone, Sone unfollowedSone) { - checkNotNull(sone, "sone must not be null"); - checkNotNull(unfollowedSone, "unfollowedSone must not be null"); - sone.removeFriend(unfollowedSone.getId()); + sone.removeFriend(soneId); boolean unfollowedSoneStillFollowed = false; for (Sone localSone : getLocalSones()) { - unfollowedSoneStillFollowed |= localSone.hasFriend(unfollowedSone.getId()); + unfollowedSoneStillFollowed |= localSone.hasFriend(soneId); } if (!unfollowedSoneStillFollowed) { synchronized (soneFollowingTimes) { - soneFollowingTimes.remove(unfollowedSone); + soneFollowingTimes.remove(soneId); } } touchConfiguration(); @@ -1108,18 +1072,16 @@ public class Core extends AbstractService implements SoneProvider, PostProvider List storedPosts = storedSone.getPosts(); synchronized (knownPosts) { for (Post post : sone.getPosts()) { - PostBuilder postBuilder = postBuilderFactory.newPostBuilder(); - postBuilder.copyPost(post).from(storedSone); - Post newPost = postBuilder.build().setKnown(knownPosts.contains(post.getId())); - if (!storedPosts.contains(newPost)) { - if (newPost.getTime() < getSoneFollowingTime(sone)) { - knownPosts.add(newPost.getId()); - newPost.setKnown(true); - } else if (!knownPosts.contains(newPost.getId())) { - eventBus.post(new NewPostFoundEvent(newPost)); + post.setKnown(knownPosts.contains(post.getId())); + if (!storedPosts.contains(post)) { + if (post.getTime() < getSoneFollowingTime(sone)) { + knownPosts.add(post.getId()); + post.setKnown(true); + } else if (!knownPosts.contains(post.getId())) { + eventBus.post(new NewPostFoundEvent(post)); } } - posts.put(newPost.getId(), newPost); + posts.put(post.getId(), post); } } } @@ -1135,7 +1097,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider Set storedReplies = storedSone.getReplies(); synchronized (knownReplies) { for (PostReply reply : sone.getReplies()) { - reply.setSone(storedSone).setKnown(knownReplies.contains(reply.getId())); + reply.setKnown(knownReplies.contains(reply.getId())); if (!storedReplies.contains(reply)) { if (reply.getTime() < getSoneFollowingTime(sone)) { knownReplies.add(reply.getId()); @@ -1164,36 +1126,8 @@ public class Core extends AbstractService implements SoneProvider, PostProvider } } } - synchronized (storedSone) { - if (!soneRescueMode || (sone.getTime() > storedSone.getTime())) { - storedSone.setTime(sone.getTime()); - } - storedSone.setClient(sone.getClient()); - storedSone.setProfile(sone.getProfile()); - if (soneRescueMode) { - for (Post post : sone.getPosts()) { - storedSone.addPost(post); - } - for (PostReply reply : sone.getReplies()) { - storedSone.addReply(reply); - } - for (String likedPostId : sone.getLikedPostIds()) { - storedSone.addLikedPostId(likedPostId); - } - for (String likedReplyId : sone.getLikedReplyIds()) { - storedSone.addLikedReplyId(likedReplyId); - } - for (Album album : sone.getAlbums()) { - storedSone.addAlbum(album); - } - } else { - storedSone.setPosts(sone.getPosts()); - storedSone.setReplies(sone.getReplies()); - storedSone.setLikePostIds(sone.getLikedPostIds()); - storedSone.setLikeReplyIds(sone.getLikedReplyIds()); - storedSone.setAlbums(sone.getAlbums()); - } - storedSone.setLatestEdition(sone.getLatestEdition()); + synchronized (sones) { + sones.put(sone.getId(), sone); } } } @@ -1312,9 +1246,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider logger.log(Level.WARNING, "Invalid post found, aborting load!"); return; } - PostBuilder postBuilder = postBuilder().withId(postId).from(sone).withTime(postTime).withText(postText); + PostBuilder postBuilder = postBuilder().withId(postId).from(sone.getId()).withTime(postTime).withText(postText); if ((postRecipientId != null) && (postRecipientId.length() == 43)) { - postBuilder.to(getSone(postRecipientId)); + postBuilder.to(postRecipientId); } posts.add(postBuilder.build()); } @@ -1334,7 +1268,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider logger.log(Level.WARNING, "Invalid reply found, aborting load!"); return; } - replies.add(getPostReply(replyId, true).setSone(sone).setPost(getPost(postId)).setTime(replyTime).setText(replyText)); + PostReplyBuilder postReplyBuilder = postReplyBuilderFactory.newPostReplyBuilder(); + postReplyBuilder.withId(replyId).from(sone.getId()).to(postId).withTime(replyTime).withText(replyText); + replies.add(postReplyBuilder.build()); } /* load post likes. */ @@ -1539,9 +1475,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider return null; } PostBuilder postBuilder = postBuilderFactory.newPostBuilder(); - postBuilder.from(sone).randomId().withTime(time).withText(text.trim()); + postBuilder.from(sone.getId()).randomId().withTime(time).withText(text.trim()); if (recipient != null) { - postBuilder.to(recipient); + postBuilder.to(recipient.getId()); } final Post post = postBuilder.build(); synchronized (posts) { @@ -1659,30 +1595,15 @@ public class Core extends AbstractService implements SoneProvider, PostProvider * @return The created reply */ public PostReply createReply(Sone sone, Post post, String text) { - return createReply(sone, post, System.currentTimeMillis(), text); - } - - /** - * Creates a new reply. - * - * @param sone - * The Sone that creates the reply - * @param post - * The post that this reply refers to - * @param time - * The time of the reply - * @param text - * The text of the reply - * @return The created reply - */ - public PostReply createReply(Sone sone, Post post, long time, String text) { checkNotNull(text, "text must not be null"); checkArgument(text.trim().length() > 0, "text must not be empty"); if (!sone.isLocal()) { logger.log(Level.FINE, String.format("Tried to create reply for non-local Sone: %s", sone)); return null; } - final PostReply reply = new PostReplyImpl(sone, post, System.currentTimeMillis(), text.trim()); + PostReplyBuilder postReplyBuilder = postReplyBuilderFactory.newPostReplyBuilder(); + postReplyBuilder.randomId().from(sone.getId()).to(post.getId()).currentTime().withText(text.trim()); + final PostReply reply = postReplyBuilder.build(); synchronized (replies) { replies.put(reply.getId(), reply); } @@ -1954,6 +1875,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider webOfTrustUpdater.stop(); updateChecker.stop(); soneDownloader.stop(); + soneDownloaders.shutdown(); identityManager.stop(); } @@ -2020,7 +1942,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider for (PostReply reply : sone.getReplies()) { String replyPrefix = sonePrefix + "/Replies/" + replyCounter++; configuration.getStringValue(replyPrefix + "/ID").setValue(reply.getId()); - configuration.getStringValue(replyPrefix + "/Post/ID").setValue(reply.getPost().getId()); + configuration.getStringValue(replyPrefix + "/Post/ID").setValue(reply.getPostId()); configuration.getLongValue(replyPrefix + "/Time").setValue(reply.getTime()); configuration.getStringValue(replyPrefix + "/Text").setValue(reply.getText()); } @@ -2138,8 +2060,8 @@ public class Core extends AbstractService implements SoneProvider, PostProvider /* save Sone following times. */ soneCounter = 0; synchronized (soneFollowingTimes) { - for (Entry soneFollowingTime : soneFollowingTimes.entrySet()) { - configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").setValue(soneFollowingTime.getKey().getId()); + for (Entry soneFollowingTime : soneFollowingTimes.entrySet()) { + configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").setValue(soneFollowingTime.getKey()); configuration.getLongValue("SoneFollowingTimes/" + soneCounter + "/Time").setValue(soneFollowingTime.getValue()); ++soneCounter; } @@ -2262,7 +2184,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider logger.log(Level.WARNING, String.format("Ignoring Sone with invalid ID: %s", soneId)); } else { synchronized (soneFollowingTimes) { - soneFollowingTimes.put(getSone(soneId), time); + soneFollowingTimes.put(soneId, time); } } ++soneCounter; @@ -2322,23 +2244,6 @@ public class Core extends AbstractService implements SoneProvider, PostProvider } /** - * Generate a Sone URI from the given URI and latest edition. - * - * @param uriString - * The URI to derive the Sone URI from - * @return The derived URI - */ - private static FreenetURI getSoneUri(String uriString) { - try { - FreenetURI uri = new FreenetURI(uriString).setDocName("Sone").setMetaString(new String[0]); - return uri; - } catch (MalformedURLException mue1) { - logger.log(Level.WARNING, String.format("Could not create Sone URI from URI: %s", uriString), mue1); - return null; - } - } - - /** * Notifies the core that a new {@link OwnIdentity} was added. * * @param ownIdentityAddedEvent