wip on server side of feeds for plugin

This commit is contained in:
Zlatin Balevsky
2020-03-12 22:28:11 +00:00
parent 14546737fd
commit 54abf82a91
6 changed files with 380 additions and 6 deletions

View File

@@ -118,7 +118,7 @@ public class Core {
private final ConnectionAcceptor connectionAcceptor
private final ConnectionEstablisher connectionEstablisher
private final HasherService hasherService
private final DownloadManager downloadManager
final DownloadManager downloadManager
private final DirectoryWatcher directoryWatcher
final FileManager fileManager
final UploadManager uploadManager

View File

@@ -242,4 +242,8 @@ public class DownloadManager {
downloaders.values().each { it.stop() }
Downloader.executorService.shutdownNow()
}
public boolean isDownloading(InfoHash infoHash) {
downloaders.containsKey(infoHash)
}
}

View File

@@ -0,0 +1,103 @@
package com.muwire.webui;
import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.muwire.core.Core;
import com.muwire.core.Persona;
import com.muwire.core.filefeeds.Feed;
import com.muwire.core.filefeeds.FeedFetchEvent;
import com.muwire.core.filefeeds.FeedItem;
import com.muwire.core.filefeeds.FeedItemFetchedEvent;
import com.muwire.core.filefeeds.FeedLoadedEvent;
import com.muwire.core.filefeeds.UIDownloadFeedItemEvent;
import com.muwire.core.filefeeds.UIFeedConfigurationEvent;
import com.muwire.core.filefeeds.UIFeedDeletedEvent;
public class FeedManager {
private final Core core;
private final Map<Persona, RemoteFeed> remoteFeeds = new ConcurrentHashMap<>();
public FeedManager(Core core) {
this.core = core;
}
public Map<Persona, RemoteFeed> getRemoteFeeds() {
return remoteFeeds;
}
public void onFeedLoadedEvent(FeedLoadedEvent e) {
remoteFeeds.put(e.getFeed().getPublisher(), new RemoteFeed(e.getFeed()));
}
public void onUIFeedConfigurationEvent(UIFeedConfigurationEvent e) {
if (!e.isNewFeed())
return;
remoteFeeds.put(e.getFeed().getPublisher(), new RemoteFeed(e.getFeed()));
}
public void onFeedFetchEvent(FeedFetchEvent e) {
RemoteFeed feed = remoteFeeds.get(e.getHost());
if (feed == null)
return; // hmm
feed.getFeed().setStatus(e.getStatus());
feed.revision++;
}
public void onFeedItemFetchedEvent(FeedItemFetchedEvent e) {
FeedItem item = e.getItem();
RemoteFeed feed = remoteFeeds.get(item.getPublisher());
if (feed == null)
return; // hmm
if (feed.getFeed().isAutoDownload() &&
!core.getFileManager().isShared(item.getInfoHash()) &&
!core.getDownloadManager().isDownloading(item.getInfoHash())) {
File target = new File(core.getMuOptions().getDownloadLocation(), item.getName());
UIDownloadFeedItemEvent event = new UIDownloadFeedItemEvent();
event.setItem(item);
event.setTarget(target);
event.setSequential(feed.getFeed().isSequential());
core.getEventBus().publish(event);
}
}
void subscribe(Persona publisher) {
Feed feed = new Feed(publisher);
feed.setAutoDownload(core.getMuOptions().getDefaultFeedAutoDownload());
feed.setItemsToKeep(core.getMuOptions().getDefaultFeedItemsToKeep());
feed.setUpdateInterval(core.getMuOptions().getDefaultFeedUpdateInterval());
feed.setSequential(core.getMuOptions().getDefaultFeedSequential());
UIFeedConfigurationEvent event = new UIFeedConfigurationEvent();
event.setFeed(feed);
event.setNewFeed(true);
core.getEventBus().publish(event);
}
void unsubscribe(Persona publisher) {
remoteFeeds.remove(publisher);
UIFeedDeletedEvent event = new UIFeedDeletedEvent();
event.setHost(publisher);
core.getEventBus().publish(event);
}
static class RemoteFeed {
private final Feed feed;
private volatile long revision;
RemoteFeed(Feed feed) {
this.feed = feed;
}
public Feed getFeed() {
return feed;
}
public long getRevision() {
return revision;
}
}
}

View File

@@ -0,0 +1,237 @@
package com.muwire.webui;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.text.Collator;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.muwire.core.Core;
import com.muwire.core.Persona;
import com.muwire.core.filefeeds.Feed;
import com.muwire.core.filefeeds.FeedItem;
import com.muwire.core.util.DataUtil;
import com.muwire.webui.FeedManager.RemoteFeed;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
public class FeedServlet extends HttpServlet {
private FeedManager feedManager;
private Core core;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String section = req.getParameter("section");
if (section == null) {
resp.sendError(403, "Bad section param");
return;
}
StringBuilder sb = new StringBuilder();
sb.append("<?xml version='1.0' encoding='UTF-8'?>");
if (section.equals("status")) {
List<WrappedFeed> feeds = feedManager.getRemoteFeeds().values().stream().
map(rf -> new WrappedFeed(rf, core.getFeedManager().getFeedItems(rf.getFeed().getPublisher()).size())).
collect(Collectors.toList());
FEED_COMPARATORS.sort(feeds, req);
sb.append("<Status>");
feeds.forEach(f -> f.toXML(sb));
sb.append("</Status>");
} else if (section.equals("items")) {
String publisherB64 = req.getParameter("publisher");
if (publisherB64 == null) {
resp.sendError(403, "Bad param");
return;
}
Persona publisher;
try {
publisher = new Persona(new ByteArrayInputStream(Base64.decode(publisherB64)));
} catch (Exception bad) {
resp.sendError(403, "Bad param");
return;
}
RemoteFeed feed = feedManager.getRemoteFeeds().get(publisher);
if (feed == null)
return; // hmm
List<WrappedFeedItem> items = core.getFeedManager().getFeedItems(publisher).stream().
map(item -> {
ResultStatus resultStatus = ResultStatus.AVAILABLE;
if (core.getFileManager().isShared(item.getInfoHash()))
resultStatus = ResultStatus.SHARED;
else if (core.getDownloadManager().isDownloading(item.getInfoHash()))
resultStatus = ResultStatus.DOWNLOADING;
return new WrappedFeedItem(item, resultStatus);
}).collect(Collectors.toList());
ITEM_COMPARATORS.sort(items, req);
sb.append("<Items>");
items.forEach(i -> i.toXML(sb));
sb.append("</Items>");
} else {
resp.sendError(403, "Bad section param");
return;
}
resp.setContentType("text/xml");
resp.setCharacterEncoding("UTF-8");
resp.setDateHeader("Expires", 0);
resp.setHeader("Pragma", "no-cache");
resp.setHeader("Cache-Control", "no-store, max-age=0, no-cache, must-revalidate");
byte[] out = sb.toString().getBytes("UTF-8");
resp.setContentLength(out.length);
resp.getOutputStream().write(out);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String action = req.getParameter("action");
if (action == null) {
resp.sendError(403,"Bad param");
return;
}
if (action.equals("subscribe")) {
String personaB64 = req.getParameter("host");
if (personaB64 == null) {
resp.sendError(403,"Bad param");
return;
}
Persona host;
try {
host = new Persona(new ByteArrayInputStream(Base64.decode(personaB64)));
} catch (Exception bad) {
resp.sendError(403,"Bad param");
return;
}
feedManager.subscribe(host);
Util.pause();
} else if (action.equals("unsubscribe")) {
String personaB64 = req.getParameter("host");
if (personaB64 == null) {
resp.sendError(403,"Bad param");
return;
}
Persona host;
try {
host = new Persona(new ByteArrayInputStream(Base64.decode(personaB64)));
} catch (Exception bad) {
resp.sendError(403,"Bad param");
return;
}
feedManager.unsubscribe(host);
Util.pause();
}
}
@Override
public void init(ServletConfig config) throws ServletException {
feedManager = (FeedManager) config.getServletContext().getAttribute("feedManager");
core = (Core) config.getServletContext().getAttribute("core");
}
private static final Comparator<WrappedFeed> FEED_BY_PUBLISHER = (l, r) -> {
return Collator.getInstance().compare(l.feed.getPublisher().getHumanReadableName(), r.feed.getPublisher().getHumanReadableName());
};
private static final Comparator<WrappedFeed> FEED_BY_FILES = (l, r) -> {
return Integer.compare(l.files, r.files);
};
private static final Comparator<WrappedFeed> FEED_BY_LAST_UPDATED = (l, r) -> {
return Long.compare(l.feed.getLastUpdated(), r.feed.getLastUpdated());
};
private static final Comparator<WrappedFeed> FEED_BY_STATUS = (l, r) -> {
return Collator.getInstance().compare(l.feed.getStatus().toString(), r.feed.getStatus().toString());
};
private static final ColumnComparators<WrappedFeed> FEED_COMPARATORS = new ColumnComparators<>();
static {
FEED_COMPARATORS.add("publisher", FEED_BY_PUBLISHER);
FEED_COMPARATORS.add("files", FEED_BY_FILES);
FEED_COMPARATORS.add("status", FEED_BY_STATUS);
FEED_COMPARATORS.add("lastUpdated", FEED_BY_LAST_UPDATED);
}
private static final Comparator<WrappedFeedItem> ITEM_BY_NAME = (l, r) -> {
return Collator.getInstance().compare(l.feedItem.getName(), r.feedItem.getName());
};
private static final Comparator<WrappedFeedItem> ITEM_BY_SIZE = (l, r) -> {
return Long.compare(l.feedItem.getSize(), r.feedItem.getSize());
};
private static final Comparator<WrappedFeedItem> ITEM_BY_STATUS = (l, r) -> {
return Collator.getInstance().compare(l.resultStatus.toString(), r.resultStatus.toString());
};
private static final Comparator<WrappedFeedItem> ITEM_BY_TIMESTAMP = (l, r) -> {
return Long.compare(l.feedItem.getTimestamp(), r.feedItem.getTimestamp());
};
private static final ColumnComparators<WrappedFeedItem> ITEM_COMPARATORS = new ColumnComparators<>();
static {
ITEM_COMPARATORS.add("name", ITEM_BY_NAME);
ITEM_COMPARATORS.add("size", ITEM_BY_SIZE);
ITEM_COMPARATORS.add("status", ITEM_BY_STATUS);
ITEM_COMPARATORS.add("timestamp", ITEM_BY_TIMESTAMP);
}
private static class WrappedFeedItem {
private final FeedItem feedItem;
private final ResultStatus resultStatus;
WrappedFeedItem(FeedItem feedItem, ResultStatus resultStatus) {
this.feedItem = feedItem;
this.resultStatus = resultStatus;
}
void toXML(StringBuilder sb) {
sb.append("<Item>");
sb.append("<Name>").append(Util.escapeHTMLinXML(feedItem.getName())).append("</Name>");
sb.append("<ResultStatus>").append(resultStatus).append("</ResultStatus>");
sb.append("<Size>").append(DataHelper.formatSize2Decimal(feedItem.getSize(), false)).append("</Size>");
sb.append("<Timestamp>").append(DataHelper.formatTime(feedItem.getTimestamp())).append("</Timestamp>");
sb.append("<InfoHash>").append(Base64.encode(feedItem.getInfoHash().getRoot())).append("</InfoHash>");
sb.append("<Certificates>").append(feedItem.getCertificates()).append("</Certificates>");
if (feedItem.getComment() != null)
sb.append("<Comment>").append(Util.escapeHTMLinXML(DataUtil.readi18nString(Base64.decode(feedItem.getComment())))).append("</Comment>");
sb.append("</Item>");
}
}
private static class WrappedFeed {
private final Feed feed;
private final long revision;
private final int files;
WrappedFeed(RemoteFeed rf, int files) {
this.feed = rf.getFeed();
this.revision = rf.getRevision();
this.files = files;
}
void toXML(StringBuilder sb) {
sb.append("<Feed>");
sb.append("<Publisher>").append(Util.escapeHTMLinXML(feed.getPublisher().getHumanReadableName())).append("</Publisher>");
sb.append("<PublisherB64>").append(feed.getPublisher().toBase64()).append("</PublisherB64>");
sb.append("<Files>").append(files).append("</Files>");
sb.append("<Revision>").append(revision).append("</Revision>");
sb.append("<Status>").append(feed.getStatus().toString()).append("</Status>");
sb.append("<Active>").append(feed.getStatus().isActive()).append("</Active>");
sb.append("<LastUpdated>").append(DataHelper.formatTime(feed.getLastUpdated())).append("</LastUpdated>");
sb.append("</Feed>");
}
}
}

View File

@@ -24,6 +24,10 @@ import com.muwire.core.connection.DisconnectionEvent;
import com.muwire.core.download.DownloadStartedEvent;
import com.muwire.core.filecert.CertificateFetchEvent;
import com.muwire.core.filecert.CertificateFetchedEvent;
import com.muwire.core.filefeeds.FeedFetchEvent;
import com.muwire.core.filefeeds.FeedItemFetchedEvent;
import com.muwire.core.filefeeds.FeedLoadedEvent;
import com.muwire.core.filefeeds.UIFeedConfigurationEvent;
import com.muwire.core.files.AllFilesLoadedEvent;
import com.muwire.core.files.FileDownloadedEvent;
import com.muwire.core.files.FileHashedEvent;
@@ -163,6 +167,12 @@ public class MuWireClient {
core.getEventBus().register(UploadEvent.class, uploadManager);
core.getEventBus().register(UploadFinishedEvent.class, uploadManager);
FeedManager feedManager = new FeedManager(core);
core.getEventBus().register(FeedLoadedEvent.class, feedManager);
core.getEventBus().register(UIFeedConfigurationEvent.class, feedManager);
core.getEventBus().register(FeedFetchEvent.class, feedManager);
core.getEventBus().register(FeedItemFetchedEvent.class, feedManager);
servletContext.setAttribute("searchManager", searchManager);
servletContext.setAttribute("downloadManager", downloadManager);
servletContext.setAttribute("connectionCounter", connectionCounter);
@@ -171,6 +181,7 @@ public class MuWireClient {
servletContext.setAttribute("trustManager", trustManager);
servletContext.setAttribute("certificateManager", certificateManager);
servletContext.setAttribute("uploadManager", uploadManager);
servletContext.setAttribute("feedManager", feedManager);
}
public String getHome() {

View File

@@ -103,11 +103,14 @@ public class SearchServlet extends HttpServlet {
List<Sender> senders = new ArrayList<>();
results.getBySender().forEach( (persona, resultsFromSender) -> {
UIResultEvent first = resultsFromSender.iterator().next();
Sender sender = new Sender(persona,
core.getTrustService().getLevel(persona.getDestination()),
resultsFromSender.iterator().next().getBrowse(),
first.getBrowse(),
browseManager.isBrowsing(persona),
resultsFromSender.size());
resultsFromSender.size(),
first.getFeed(),
core.getFeedManager().getFeed(persona) != null);
senders.add(sender);
});
@@ -234,7 +237,9 @@ public class SearchServlet extends HttpServlet {
browseManager.isBrowsing(event.getSender()),
event.getComment(),
event.getCertificates(),
core.getTrustService().getLevel(event.getSender().getDestination()));
core.getTrustService().getLevel(event.getSender().getDestination()),
event.getFeed(),
core.getFeedManager().getFeed(event.getSender()) != null);
sendersForResult.add(senderForResult);
});
@@ -284,13 +289,18 @@ public class SearchServlet extends HttpServlet {
private final boolean browse;
private final boolean browsing;
private final int results;
private final boolean feed;
private final boolean subscribed;
Sender(Persona persona, TrustLevel trustLevel, boolean browse, boolean browsing, int results) {
Sender(Persona persona, TrustLevel trustLevel, boolean browse, boolean browsing, int results,
boolean feed, boolean subscribed) {
this.persona = persona;
this.trustLevel = trustLevel;
this.browse = browse;
this.browsing = browsing;
this.results = results;
this.feed = feed;
this.subscribed = subscribed;
}
void toXML(StringBuilder sb) {
@@ -301,6 +311,8 @@ public class SearchServlet extends HttpServlet {
sb.append("<Browse>").append(browse).append("</Browse>");
sb.append("<Browsing>").append(browsing).append("</Browsing>");
sb.append("<Results>").append(results).append("</Results>");
sb.append("<Feed>").append(feed).append("</Feed>");
sb.append("<Subscribed>").append(subscribed).append("</Subscribed>");
sb.append("</Sender>");
}
}
@@ -369,14 +381,19 @@ public class SearchServlet extends HttpServlet {
private final String comment;
private final int certificates;
private final TrustLevel trustLevel;
private final boolean feed;
private final boolean subscribed;
SenderForResult(Persona sender, boolean browse, boolean browsing, String comment, int certificates, TrustLevel trustLevel) {
SenderForResult(Persona sender, boolean browse, boolean browsing, String comment, int certificates, TrustLevel trustLevel,
boolean feed, boolean subscribed) {
this.sender = sender;
this.browse = browse;
this.trustLevel = trustLevel;
this.browsing = browsing;
this.comment = comment;
this.certificates = certificates;
this.feed = feed;
this.subscribed = subscribed;
}
void toXML(StringBuilder sb) {
@@ -389,6 +406,8 @@ public class SearchServlet extends HttpServlet {
if (comment != null)
sb.append("<Comment>").append(Util.escapeHTMLinXML(comment)).append("</Comment>");
sb.append("<Certificates>").append(certificates).append("</Certificates>");
sb.append("<Feed>").append(feed).append("</Feed>");
sb.append("<Subscribed>").append(subscribed).append("</Subscribed>");
sb.append("</Sender>");
}