package com.frostwire.jlibtorrent;
import com.frostwire.jlibtorrent.alerts.Alert;
import com.frostwire.jlibtorrent.alerts.DhtImmutableItemAlert;
import com.frostwire.jlibtorrent.swig.char_vector;
import com.frostwire.jlibtorrent.swig.dht_item;
import com.frostwire.jlibtorrent.swig.sha1_hash;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static com.frostwire.jlibtorrent.alerts.AlertType.DHT_IMMUTABLE_ITEM;
/**
* This class provides a lens only functionality.
*
* @author gubatron
* @author aldenml
*/
public final class DHT {
private static final int[] DHT_IMMUTABLE_ITEM_TYPES = {DHT_IMMUTABLE_ITEM.getSwig()};
private final Session s;
public DHT(Session s) {
this.s = s;
}
public void start() {
s.startDHT();
}
public void stop() {
s.stopDHT();
}
public boolean isRunning() {
return s.isDHTRunning();
}
public void waitNodes(int nodes) {
boolean ready = false;
while (!ready) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// ignore
}
ready = s.getStatus().getDHTNodes() > nodes;
}
}
public int nodes() {
return s.getStatus().getDHTNodes();
}
public void get(String sha1) {
s.dhtGetItem(new Sha1Hash(sha1));
}
public Entry get(String sha1, long timeout, TimeUnit unit) {
final Sha1Hash target = new Sha1Hash(sha1);
final Entry[] result = {null};
final CountDownLatch signal = new CountDownLatch(1);
AlertListener l = new AlertListener() {
@Override
public int[] types() {
return DHT_IMMUTABLE_ITEM_TYPES;
}
@Override
public void alert(Alert<?> alert) {
if (alert instanceof DhtImmutableItemAlert) {
DhtImmutableItemAlert itemAlert = (DhtImmutableItemAlert) alert;
if (target.equals(itemAlert.getTarget())) {
result[0] = itemAlert.getItem();
signal.countDown();
}
}
}
};
s.addListener(l);
s.dhtGetItem(target);
try {
signal.await(timeout, unit);
} catch (InterruptedException e) {
// ignore
}
s.removeListener(l);
return result[0];
}
public String put(Entry entry) {
return s.dhtPutItem(entry).toString();
}
public void getPeers(String sha1) {
s.dhtGetPeers(new Sha1Hash(sha1));
}
public void announce(String sha1, int port, int flags) {
s.dhtAnnounce(new Sha1Hash(sha1), port, flags);
}
public void announce(String sha1) {
s.dhtAnnounce(new Sha1Hash(sha1));
}
/**
* calculate the target hash for an immutable item.
*
* @param e
* @return
*/
public static Sha1Hash itemTargetId(Entry e) {
return new Sha1Hash(dht_item.item_target_id(e.getSwig().bencode()));
}
/**
* calculate the target hash for a mutable item.
*
* @param salt
* @param pk
* @return
*/
public static Sha1Hash itemTargetId(String salt, byte[] pk) {
sha1_hash h = dht_item.item_target_id(Vectors.string2char_vector(salt), Vectors.bytes2char_vector(pk));
return new Sha1Hash(h);
}
/**
* Given a byte range ``v`` and an optional byte range ``salt``, a
* sequence number, public key ``pk`` (must be 32 bytes) and a secret key
* ``sk`` (must be 64 bytes), this function produces a signature which
* is written into a 64 byte buffer pointed to by ``sig``. The caller
* is responsible for allocating the destination buffer that's passed in
* as the ``sig`` argument. Typically it would be allocated on the stack.
*
* @param e
* @param salt
* @param seq
* @param pk
* @param sk
* @param sig
*/
public static void signMutableItem(Entry e, String salt, int seq, byte[] pk, byte[] sk, byte[] sig) {
if (sig == null || sig.length != Ed25519.SIGNATURE_SIZE) {
throw new IllegalArgumentException("The signature array must be a valid one with length " + Ed25519.SIGNATURE_SIZE);
}
char_vector sig_v = Vectors.new_char_vector(Ed25519.SIGNATURE_SIZE);
dht_item.sign_mutable_item(e.getSwig().bencode(), salt, seq,
Vectors.bytes2char_vector(pk), Vectors.bytes2char_vector(sk), sig_v);
Vectors.char_vector2bytes(sig_v, sig);
}
public static boolean verifyMutableItem(Entry e, String salt, int seq, byte[] pk, byte[] sig) {
return dht_item.verify_mutable_item(e.getSwig().bencode(), salt, seq,
Vectors.bytes2char_vector(pk),
Vectors.bytes2char_vector(sig));
}
public static int canonicalString(Entry e, int seq, String salt, byte[] out) {
if (out == null || out.length != 1200) {
throw new IllegalArgumentException("The out array must be a valid one with length 1200");
}
char_vector out_v = Vectors.new_char_vector(1200);
int r = dht_item.canonical_string(e.getSwig().bencode(),
seq, salt, out_v);
Vectors.char_vector2bytes(out_v, out);
return r;
}
}