/*
* Mojito Distributed Hash Table (Mojito DHT)
* Copyright (C) 2006-2007 LimeWire LLC
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.limewire.mojito;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.security.MessageDigest;
import java.util.concurrent.Future;
import org.limewire.io.SecureInputStream;
import org.limewire.io.SecureOutputStream;
import org.limewire.mojito.db.DHTValueType;
import org.limewire.mojito.db.Database;
import org.limewire.mojito.db.StorableModelManager;
import org.limewire.mojito.db.impl.DHTValueImpl;
import org.limewire.mojito.result.BootstrapResult;
import org.limewire.mojito.result.FindNodeResult;
import org.limewire.mojito.result.FindValueResult;
import org.limewire.mojito.result.PingResult;
import org.limewire.mojito.result.StoreResult;
import org.limewire.mojito.routing.RouteTable;
import org.limewire.mojito.routing.Version;
import org.limewire.mojito.routing.RouteTable.SelectMode;
import org.limewire.mojito.routing.impl.LocalContact;
import org.limewire.mojito.settings.LookupSettings;
import org.limewire.mojito.statistics.DHTStats;
import org.limewire.mojito.util.CollectionUtils;
/**
* Executes various features of the Mojito DHT. <code>CommandHandler</code>
* is useful in running the Mojito DHT from the command line.
* Additionally, <code>CommandHandler</code> writes information about
* the {@link MojitoDHT} to a {@link PrintWriter}.
*/
public class CommandHandler {
private static final String[] COMMANDS = {
"help",
"info",
"ping .+ \\d{1,5}",
"bootstrap .+ \\d{1,5}",
"put (key|kuid) (\\w|\\d)+ (value|file) .+",
"remove (key|kuid) (\\w|\\d)+",
"get (key|kuid) (\\w|\\d)+",
"lookup (key|kuid) (\\w|\\d)+",
"database",
"publisher",
"routetable",
"store .+",
"load .+",
"kill",
"stats",
"restart",
"firewalled",
"exhaustive",
"id .+",
"select .+",
"nextid",
"rt_gui",
"arcs_gui",
"test",
"bootstrapped"
};
public static boolean handle(MojitoDHT dht, String command, PrintWriter out) {
try {
command = command.trim();
for (String c : COMMANDS) {
if (command.matches(c)) {
String[] args = command.split(" ");
Method m = CommandHandler.class.getDeclaredMethod(args[0], MojitoDHT.class, String[].class, PrintWriter.class);
m.invoke(null, dht, args, out);
return true;
}
}
} catch (NoSuchMethodException err) {
err.printStackTrace(out);
} catch (InvocationTargetException err) {
err.printStackTrace(out);
} catch (IllegalAccessException err) {
err.printStackTrace(out);
} finally {
out.flush();
}
return false;
}
public static void help(MojitoDHT dht, String[] args, PrintWriter out) {
for (String c : COMMANDS) {
out.println(c);
}
}
public static void info(MojitoDHT dht, String[] args, PrintWriter out) {
out.println(dht.toString());
}
public static void exhaustive(MojitoDHT dht, String[] args, PrintWriter out) {
boolean current = LookupSettings.EXHAUSTIVE_VALUE_LOOKUP.getValue();
LookupSettings.EXHAUSTIVE_VALUE_LOOKUP.setValue(
!LookupSettings.EXHAUSTIVE_VALUE_LOOKUP.getValue());
out.println("Exhaustive: " + current + " -> " + LookupSettings.EXHAUSTIVE_VALUE_LOOKUP.getValue());
}
public static void firewalled(MojitoDHT dht, String[] args, PrintWriter out) {
((LocalContact)dht.getLocalNode()).setFirewalled(!dht.isFirewalled());
out.println("Firewalled: " + dht.isFirewalled());
}
public static void database(MojitoDHT dht, String[] args, PrintWriter out) {
StringBuilder buffer = new StringBuilder("\n");
Database database = dht.getDatabase();
buffer.append(database.toString());
out.println(buffer);
}
public static void publisher(MojitoDHT dht, String[] args, PrintWriter out) {
StringBuilder buffer = new StringBuilder("\n");
StorableModelManager modelManager = dht.getStorableModelManager();
buffer.append(modelManager.toString());
out.println(buffer);
}
public static void routetable(MojitoDHT dht, String[] args, PrintWriter out) {
StringBuilder buffer = new StringBuilder("\n");
RouteTable routingTable = dht.getRouteTable();
buffer.append(routingTable.toString());
out.println(buffer);
}
public static Future<PingResult> ping(MojitoDHT dht, String[] args, final PrintWriter out) {
String host = args[1];
int port = Integer.parseInt(args[2]);
SocketAddress addr = new InetSocketAddress(host, port);
out.println("Pinging... " + addr);
Future<PingResult> future = dht.ping(addr);
try {
PingResult result = future.get();
out.println(result);
} catch (Exception err) {
err.printStackTrace(out);
}
out.flush();
return future;
}
public static void bootstrap(MojitoDHT dht, String[] args, final PrintWriter out) {
String host = args[1];
int port = Integer.parseInt(args[2]);
SocketAddress addr = new InetSocketAddress(host, port);
out.println("Bootstrapping... " + addr);
try {
PingResult pong = dht.ping(addr).get();
BootstrapResult result = dht.bootstrap(pong.getContact()).get();
out.println("Bootstraping finished:\n" + result);
out.flush();
} catch (Exception e) {
e.printStackTrace(out);
}
}
public static void put(MojitoDHT dht, String[] args, final PrintWriter out) {
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
KUID key = null;
byte[] value = null;
if (args[1].equals("kuid")) {
key = KUID.createWithHexString(args[2]);
} else {
key = KUID.createWithBytes(md.digest(args[2].getBytes("UTF-8")));
}
md.reset();
if (args[3].equals("value")) {
value = args[4].getBytes("UTF-8");
} else if (args[3].equals("file")) {
File file = new File(args[4]);
byte[] data = new byte[(int)Math.min(1024, file.length())];
FileInputStream in = new FileInputStream(file);
in.read(data, 0, data.length);
in.close();
value = data;
}
md.reset();
out.println("Storing... " + key);
StoreResult evt = dht.put(key, new DHTValueImpl(DHTValueType.TEST, Version.ZERO, value)).get();
StringBuilder buffer = new StringBuilder();
buffer.append("STORE RESULT:\n");
buffer.append(evt.toString());
out.println(buffer.toString());
} catch (Exception err) {
err.printStackTrace(out);
}
}
public static void remove(MojitoDHT dht, String[] args, final PrintWriter out) {
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
KUID key = null;
if (args[1].equals("kuid")) {
key = KUID.createWithHexString(args[2]);
} else {
key = KUID.createWithBytes(md.digest(args[2].getBytes("UTF-8")));
}
md.reset();
out.println("Removing... " + key);
StoreResult evt = dht.remove(key).get();
StringBuilder buffer = new StringBuilder();
buffer.append("REMOVE RESULT:\n");
buffer.append(evt.toString());
out.println(buffer.toString());
} catch (Exception e) {
e.printStackTrace(out);
}
}
public static void get(MojitoDHT dht, String[] args, PrintWriter out) {
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
KUID key = null;
if (args[1].equals("kuid")) {
key = KUID.createWithHexString(args[2]);
} else {
key = KUID.createWithBytes(md.digest(args[2].getBytes("UTF-8")));
}
md.reset();
EntityKey lookupKey = EntityKey.createEntityKey(key, DHTValueType.ANY);
FindValueResult evt = dht.get(lookupKey).get();
out.println(evt.toString());
} catch (Exception e) {
e.printStackTrace(out);
}
}
public static void lookup(MojitoDHT dht, String[] args, PrintWriter out) {
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
KUID key = null;
if (args[1].equals("kuid")) {
key = KUID.createWithHexString(args[2]);
} else {
key = KUID.createWithBytes(md.digest(args[2].getBytes("UTF-8")));
}
md.reset();
FindNodeResult evt = ((Context)dht).lookup(key).get();
out.println(evt.toString());
} catch (Exception e) {
e.printStackTrace(out);
}
}
public static MojitoDHT load(MojitoDHT dht, String[] args, PrintWriter out) throws Exception {
File file = new File(args[1]);
out.println("Loading: " + file);
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(
new BufferedInputStream(
new SecureInputStream(
new FileInputStream(file))));
RouteTable routeTable = (RouteTable)ois.readObject();
Database database = (Database)ois.readObject();
MojitoDHT mojito = MojitoFactory.createDHT(dht.getName());
synchronized (mojito) {
mojito.setRouteTable(routeTable);
mojito.setDatabase(database);
}
return mojito;
} finally {
try {
if (ois != null) { ois.close(); }
} catch (IOException ignore) {}
}
}
public static void store(MojitoDHT dht, String[] args, PrintWriter out) throws IOException {
File file = new File(args[1]);
out.println("Storing: " + file);
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(
new BufferedOutputStream(
new SecureOutputStream(
new FileOutputStream(file))));
synchronized (dht) {
oos.writeObject(dht.getRouteTable());
oos.writeObject(dht.getDatabase());
}
oos.flush();
} finally {
try {
if (oos != null) { oos.close(); }
} catch (IOException ignore) {}
}
}
public static void stats(MojitoDHT dht, String[] args, PrintWriter out) throws IOException {
DHTStats stats = ((Context)dht).getDHTStats();
stats.dump(out, true);
}
public static void id(MojitoDHT dht, String[] args, PrintWriter out) throws Exception {
KUID nodeId = KUID.createWithHexString(args[1]);
out.println("Setting NodeID to: " + nodeId);
Method m = dht.getClass().getDeclaredMethod("setLocalNodeID", new Class[]{KUID.class});
m.setAccessible(true);
m.invoke(dht, new Object[]{nodeId});
}
public static void select(MojitoDHT dht, String[] args, PrintWriter out) throws Exception {
KUID nodeId = KUID.createWithHexString(args[1]);
out.println("Selecting: " + nodeId);
RouteTable routeTable = ((Context)dht).getRouteTable();
out.println(CollectionUtils.toString(routeTable.select(nodeId, 20, SelectMode.ALL)));
}
public static void nextid(MojitoDHT dht, String[] args, PrintWriter out) throws Exception {
((Context)dht).getLocalNode().nextInstanceID();
}
public static void kill(MojitoDHT dht, String[] args, PrintWriter out) throws Exception {
if (dht.isRunning()) {
out.println("Stopping " + dht.getName());
dht.stop();
}
}
public static void restart(MojitoDHT dht, String[] args, PrintWriter out) throws Exception {
if (!dht.isRunning()) {
out.println("Starting " + dht.getName());
dht.start();
}
}
@SuppressWarnings("unchecked")
public static void rt_gui(MojitoDHT dht, String[] args, PrintWriter out) throws Exception {
Class clazz = Class.forName("org.limewire.mojito.visual.RouteTableVisualizer");
Method show = clazz.getDeclaredMethod("show", Context.class);
show.invoke(null, dht);
}
@SuppressWarnings("unchecked")
public static void arcs_gui(MojitoDHT dht, String[] args, PrintWriter out) throws Exception {
Class clazz = Class.forName("org.limewire.mojito.visual.ArcsVisualizer");
Method show = clazz.getDeclaredMethod("show", Context.class);
show.invoke(null, dht);
}
public static void bootstrapped(MojitoDHT dht, String[] args, PrintWriter out) throws Exception {
Context context = (Context)dht;
boolean bootstrapped = context.isBootstrapped();
context.setBootstrapped(!bootstrapped);
out.println(bootstrapped + " -> " + (!bootstrapped));
}
}