DumpDirectoryAction.java
package emissary.server.mvc;
import emissary.core.EmissaryException;
import emissary.core.Namespace;
import emissary.core.NamespaceException;
import emissary.directory.DirectoryEntry;
import emissary.directory.DirectoryPlace;
import emissary.directory.IDirectoryPlace;
import emissary.directory.KeyManipulator;
import emissary.server.mvc.adapters.DirectoryAdapter;
import emissary.server.mvc.adapters.RequestUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import org.glassfish.jersey.server.mvc.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
@Path("")
// context is emissary
public class DumpDirectoryAction {
private static final Logger LOG = LoggerFactory.getLogger(DumpDirectoryAction.class);
@GET
@Path("/DumpDirectory.action")
@Produces(MediaType.TEXT_HTML)
@Template(name = "/dump_directory")
public Map<String, Object> dumpDirectory(@Context HttpServletRequest request, @Nullable @QueryParam("targetDir") String targetDir) {
Map<String, Object> map = new HashMap<>();
IDirectoryPlace dir = null;
List<String> errors = new ArrayList<>();
String cleanTargetDirectory = RequestUtil.sanitizeParameter(targetDir);
// get top level
if (cleanTargetDirectory == null) {
LOG.debug("Lookup is using default name since no {} was specified", DirectoryAdapter.TARGET_DIRECTORY);
try {
dir = DirectoryPlace.lookup();
} catch (EmissaryException e) {
LOG.error("DirectoryPlace lookup error", e);
errors.add("DirectoryPlace lookup error: " + e.getMessage());
}
} else {
LOG.debug("Lookup is using directory name {}", cleanTargetDirectory);
try {
dir = (IDirectoryPlace) Namespace.lookup(cleanTargetDirectory);
} catch (NamespaceException e) {
LOG.error("Namespace lookup error for {}", cleanTargetDirectory, e);
errors.add("Namespace lookup error: " + e.getMessage());
}
}
if (dir != null) {
LOG.debug("Lookup returned {}", dir);
map.put("directory-label", dir.toString());
}
int rowCount = 0;
List<DirectoryInfo> entryKeys = new ArrayList<>();
long now = System.currentTimeMillis();
if (dir != null) {
for (String dataId : dir.getEntryKeys()) {
LOG.trace("dataId key is {}", dataId);
List<DirectoryEntryInfo> list = new ArrayList<>();
for (DirectoryEntry entry : dir.getEntryList(dataId)) {
LOG.trace("Found entry {}", entry);
list.add(new DirectoryEntryInfo(rowCount++ % 2 == 0 ? "even" : "odd", entry, now));
}
entryKeys.add(new DirectoryInfo(dataId, list));
}
}
if (!entryKeys.isEmpty()) {
map.put("entrykeys", entryKeys);
} else {
LOG.debug("Found no entry keys");
}
List<PeerInfo> peers = new ArrayList<>();
if (dir != null) {
for (String peerkey : dir.getPeerDirectories()) {
peers.add(new PeerInfo(peerkey, dir.isRemoteDirectoryAvailable(peerkey)));
}
}
if (!peers.isEmpty()) {
map.put("peers", peers);
}
if (!errors.isEmpty()) {
map.put("error", true);
map.put("errors", errors);
}
return map;
}
// TODO: move these to proper response objects
public static class PeerInfo {
final String link;
final String peerkey;
final String status;
public PeerInfo(String peerkey, boolean healthy) {
this.peerkey = peerkey;
this.link =
KeyManipulator.getServiceHostUrl(peerkey) + "emissary/DumpDirectory.action?targetDir="
+ KeyManipulator.getServiceLocation(peerkey);
this.status = healthy ? "" : "DOWN";
}
}
public static class DirectoryInfo {
final String dataId;
final List<DirectoryEntryInfo> entrylist;
public DirectoryInfo(String dataId, List<DirectoryEntryInfo> list) {
this.dataId = dataId;
this.entrylist = list;
}
}
public static class DirectoryEntryInfo {
final String stripe;
final String key;
final int cost;
final int quality;
final int expense;
final String age;
public DirectoryEntryInfo(String stripe, DirectoryEntry entry, long now) {
this.stripe = stripe;
this.key = entry.getKey();
this.cost = entry.getCost();
this.quality = entry.getQuality();
this.expense = entry.getExpense();
long ago = now - entry.getAge();
long hh = ago / 3600000;
long mm = (ago % 3600000) / 60000;
long ss = (ago % 60000) / 1000;
String hhs = (hh < 10 ? "0" : "") + hh;
String mms = (mm < 10 ? "0" : "") + mm;
String sss = (ss < 10 ? "0" : "") + ss;
this.age = hhs + ":" + mms + ":" + sss;
}
}
}