mirror of
https://github.com/ChronosX88/KademliaDHT.git
synced 2024-11-22 02:02:21 +00:00
Problem with serializing the DHT also, had to create a DHT specific Serializer class
This commit is contained in:
parent
e2ca9326c9
commit
22fee9116a
@ -25,6 +25,7 @@ import kademlia.operation.Operation;
|
|||||||
import kademlia.operation.KadRefreshOperation;
|
import kademlia.operation.KadRefreshOperation;
|
||||||
import kademlia.operation.StoreOperation;
|
import kademlia.operation.StoreOperation;
|
||||||
import kademlia.routing.RoutingTable;
|
import kademlia.routing.RoutingTable;
|
||||||
|
import kademlia.serializer.JsonDHTSerializer;
|
||||||
import kademlia.serializer.JsonRoutingTableSerializer;
|
import kademlia.serializer.JsonRoutingTableSerializer;
|
||||||
import kademlia.serializer.JsonSerializer;
|
import kademlia.serializer.JsonSerializer;
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ import kademlia.serializer.JsonSerializer;
|
|||||||
* @todo If we're trying to send a message to this node, just cancel the sending process and handle the message right here
|
* @todo If we're trying to send a message to this node, just cancel the sending process and handle the message right here
|
||||||
* @todo Keep this node in it's own routing table - it helps for ContentRefresh operation - easy to check whether this node is one of the k-nodes for a content
|
* @todo Keep this node in it's own routing table - it helps for ContentRefresh operation - easy to check whether this node is one of the k-nodes for a content
|
||||||
* @todo Move DHT.getContentStorageFolderName to the Configuration class
|
* @todo Move DHT.getContentStorageFolderName to the Configuration class
|
||||||
|
* @todo Implement Kademlia.ping() operation.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class Kademlia
|
public class Kademlia
|
||||||
@ -152,7 +154,7 @@ public class Kademlia
|
|||||||
* @section Read the DHT
|
* @section Read the DHT
|
||||||
*/
|
*/
|
||||||
din = new DataInputStream(new FileInputStream(getStateStorageFolderName(ownerId) + File.separator + "dht.kns"));
|
din = new DataInputStream(new FileInputStream(getStateStorageFolderName(ownerId) + File.separator + "dht.kns"));
|
||||||
DHT idht = new JsonSerializer<DHT>().read(din);
|
DHT idht = new JsonDHTSerializer().read(din);
|
||||||
System.out.println("Finished reading data.");
|
System.out.println("Finished reading data.");
|
||||||
return new Kademlia(ownerId, inode, ikad.getPort(), idht);
|
return new Kademlia(ownerId, inode, ikad.getPort(), idht);
|
||||||
}
|
}
|
||||||
@ -319,7 +321,7 @@ public class Kademlia
|
|||||||
* @section Save the DHT
|
* @section Save the DHT
|
||||||
*/
|
*/
|
||||||
dout = new DataOutputStream(new FileOutputStream(getStateStorageFolderName(this.ownerId) + File.separator + "dht.kns"));
|
dout = new DataOutputStream(new FileOutputStream(getStateStorageFolderName(this.ownerId) + File.separator + "dht.kns"));
|
||||||
new JsonSerializer<DHT>().write(this.dht, dout);
|
new JsonDHTSerializer().write(this.dht, dout);
|
||||||
|
|
||||||
System.out.println("FInished saving state");
|
System.out.println("FInished saving state");
|
||||||
|
|
||||||
@ -381,6 +383,11 @@ public class Kademlia
|
|||||||
sb.append(this.localNode.getRoutingTable());
|
sb.append(this.localNode.getRoutingTable());
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
|
|
||||||
|
sb.append("\n");
|
||||||
|
sb.append("DHT: ");
|
||||||
|
sb.append(this.dht);
|
||||||
|
sb.append("\n");
|
||||||
|
|
||||||
sb.append("\n\n\n");
|
sb.append("\n\n\n");
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
|
@ -23,15 +23,27 @@ import kademlia.serializer.JsonSerializer;
|
|||||||
public class DHT
|
public class DHT
|
||||||
{
|
{
|
||||||
|
|
||||||
private final StorageEntryManager entriesManager;
|
private transient StorageEntryManager entriesManager;
|
||||||
private transient final JsonSerializer<KadContent> contentSerializer;
|
private transient final JsonSerializer<KadContent> contentSerializer;
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
entriesManager = new StorageEntryManager();
|
|
||||||
contentSerializer = new JsonSerializer<>();
|
contentSerializer = new JsonSerializer<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DHT()
|
||||||
|
{
|
||||||
|
this.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize this DHT to it's default state
|
||||||
|
*/
|
||||||
|
public final void initialize()
|
||||||
|
{
|
||||||
|
entriesManager = new StorageEntryManager();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle storing content locally
|
* Handle storing content locally
|
||||||
*
|
*
|
||||||
@ -178,4 +190,24 @@ public class DHT
|
|||||||
{
|
{
|
||||||
return entriesManager.getAllEntries();
|
return entriesManager.getAllEntries();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to add a list of storage entries for existing content to the DHT.
|
||||||
|
* Mainly used when retrieving StorageEntries from a saved state file.
|
||||||
|
*
|
||||||
|
* @param ientries The entries to add
|
||||||
|
*/
|
||||||
|
public void putStorageEntries(List<StorageEntry> ientries)
|
||||||
|
{
|
||||||
|
for (StorageEntry e : ientries)
|
||||||
|
{
|
||||||
|
this.entriesManager.put(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return this.entriesManager.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,12 +70,7 @@ public class StorageEntry
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check that key matches */
|
/* Check that key matches */
|
||||||
if ((params.getKey() != null) && (!params.getKey().equals(this.key)))
|
return ((params.getKey() != null) && (!params.getKey().equals(this.key)));
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -98,4 +93,23 @@ public class StorageEntry
|
|||||||
hash = 23 * hash + Objects.hashCode(this.type);
|
hash = 23 * hash + Objects.hashCode(this.type);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder("[StorageEntry: ");
|
||||||
|
|
||||||
|
sb.append("{Key: ");
|
||||||
|
sb.append(this.key);
|
||||||
|
sb.append("} ");
|
||||||
|
sb.append("{Owner: ");
|
||||||
|
sb.append(this.ownerId);
|
||||||
|
sb.append("} ");
|
||||||
|
sb.append("{Type: ");
|
||||||
|
sb.append(this.type);
|
||||||
|
sb.append("} ");
|
||||||
|
sb.append("]");
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import kademlia.node.NodeId;
|
|||||||
* @author Joshua Kissoon
|
* @author Joshua Kissoon
|
||||||
* @since 20140226
|
* @since 20140226
|
||||||
*/
|
*/
|
||||||
public class StorageEntryManager
|
class StorageEntryManager
|
||||||
{
|
{
|
||||||
|
|
||||||
private final Map<NodeId, List<StorageEntry>> entries;
|
private final Map<NodeId, List<StorageEntry>> entries;
|
||||||
@ -34,6 +34,16 @@ public class StorageEntryManager
|
|||||||
public void put(KadContent content)
|
public void put(KadContent content)
|
||||||
{
|
{
|
||||||
StorageEntry entry = new StorageEntry(content);
|
StorageEntry entry = new StorageEntry(content);
|
||||||
|
this.put(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new entry to our storage
|
||||||
|
*
|
||||||
|
* @param entry The StorageEntry to store
|
||||||
|
*/
|
||||||
|
public void put(StorageEntry entry)
|
||||||
|
{
|
||||||
if (!this.entries.containsKey(entry.getKey()))
|
if (!this.entries.containsKey(entry.getKey()))
|
||||||
{
|
{
|
||||||
this.entries.put(entry.getKey(), new ArrayList<StorageEntry>());
|
this.entries.put(entry.getKey(), new ArrayList<StorageEntry>());
|
||||||
@ -116,4 +126,26 @@ public class StorageEntryManager
|
|||||||
|
|
||||||
return entriesRet;
|
return entriesRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder("Stored Content: \n");
|
||||||
|
for (List<StorageEntry> es : this.entries.values())
|
||||||
|
{
|
||||||
|
if (entries.size() < 1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (StorageEntry e : es)
|
||||||
|
{
|
||||||
|
sb.append(e);
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append("\n");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,12 +30,24 @@ public class RoutingTable
|
|||||||
this.localNode = localNode;
|
this.localNode = localNode;
|
||||||
|
|
||||||
/* Initialize all of the buckets to a specific depth */
|
/* Initialize all of the buckets to a specific depth */
|
||||||
this.initializeBuckets();
|
this.initialize();
|
||||||
|
|
||||||
/* @todo Insert the local node */
|
/* @todo Insert the local node */
|
||||||
//this.insert(localNode);
|
//this.insert(localNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the RoutingTable to it's default state
|
||||||
|
*/
|
||||||
|
public final void initialize()
|
||||||
|
{
|
||||||
|
this.buckets = new KadBucket[NodeId.ID_LENGTH];
|
||||||
|
for (int i = 0; i < NodeId.ID_LENGTH; i++)
|
||||||
|
{
|
||||||
|
buckets[i] = new KadBucket(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new node to the routing table
|
* Adds a new node to the routing table
|
||||||
*
|
*
|
||||||
@ -180,18 +192,6 @@ public class RoutingTable
|
|||||||
this.buckets = buckets;
|
this.buckets = buckets;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the kadBuckets to be empty
|
|
||||||
*/
|
|
||||||
public final void initializeBuckets()
|
|
||||||
{
|
|
||||||
this.buckets = new KadBucket[NodeId.ID_LENGTH];
|
|
||||||
for (int i = 0; i < NodeId.ID_LENGTH; i++)
|
|
||||||
{
|
|
||||||
buckets[i] = new KadBucket(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final String toString()
|
public final String toString()
|
||||||
{
|
{
|
||||||
|
94
src/kademlia/serializer/JsonDHTSerializer.java
Normal file
94
src/kademlia/serializer/JsonDHTSerializer.java
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package kademlia.serializer;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.List;
|
||||||
|
import kademlia.dht.DHT;
|
||||||
|
import kademlia.dht.StorageEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A KadSerializer that serializes DHT to JSON format
|
||||||
|
* The generic serializer is not working for DHT
|
||||||
|
*
|
||||||
|
* Why a DHT specific serializer?
|
||||||
|
* The DHT structure:
|
||||||
|
* - DHT
|
||||||
|
* -- StorageEntriesManager
|
||||||
|
* --- Map<NodeId, List<StorageEntry>>
|
||||||
|
* ---- NodeId:KeyBytes
|
||||||
|
* ---- List<StorageEntry>
|
||||||
|
* ----- StorageEntry: Key, OwnerId, Type, Hash
|
||||||
|
*
|
||||||
|
* The above structure seems to be causing some problem for Gson, especially at the Map part.
|
||||||
|
*
|
||||||
|
* Solution
|
||||||
|
* - Make the StorageEntriesManager transient
|
||||||
|
* - Simply store all StorageEntry in the serialized object
|
||||||
|
* - When reloading, re-add all StorageEntry to the DHT
|
||||||
|
*
|
||||||
|
* @author Joshua Kissoon
|
||||||
|
*
|
||||||
|
* @since 20140310
|
||||||
|
*/
|
||||||
|
public class JsonDHTSerializer implements KadSerializer<DHT>
|
||||||
|
{
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
|
private final Type storageEntriesCollectionType;
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
gson = new Gson();
|
||||||
|
|
||||||
|
storageEntriesCollectionType = new TypeToken<List<StorageEntry>>()
|
||||||
|
{
|
||||||
|
}.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(DHT data, DataOutputStream out) throws IOException
|
||||||
|
{
|
||||||
|
try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(out)))
|
||||||
|
{
|
||||||
|
writer.beginArray();
|
||||||
|
|
||||||
|
/* Write the basic DHT */
|
||||||
|
gson.toJson(data, DHT.class, writer);
|
||||||
|
|
||||||
|
/* Now Store the Entries */
|
||||||
|
gson.toJson(data.getStorageEntries(), this.storageEntriesCollectionType, writer);
|
||||||
|
|
||||||
|
writer.endArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DHT read(DataInputStream in) throws IOException, ClassNotFoundException
|
||||||
|
{
|
||||||
|
try (DataInputStream din = new DataInputStream(in);
|
||||||
|
JsonReader reader = new JsonReader(new InputStreamReader(in)))
|
||||||
|
{
|
||||||
|
reader.beginArray();
|
||||||
|
|
||||||
|
/* Read the basic DHT */
|
||||||
|
DHT dht = gson.fromJson(reader, DHT.class);
|
||||||
|
dht.initialize();
|
||||||
|
|
||||||
|
/* Now get the entries and add them back to the DHT */
|
||||||
|
List<StorageEntry> entries = gson.fromJson(reader, this.storageEntriesCollectionType);
|
||||||
|
dht.putStorageEntries(entries);
|
||||||
|
|
||||||
|
reader.endArray();
|
||||||
|
return dht;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -36,7 +36,7 @@ import kademlia.node.Node;
|
|||||||
*
|
*
|
||||||
* @author Joshua Kissoon
|
* @author Joshua Kissoon
|
||||||
*
|
*
|
||||||
* @since 20140225
|
* @since 20140310
|
||||||
*/
|
*/
|
||||||
public class JsonRoutingTableSerializer implements KadSerializer<RoutingTable>
|
public class JsonRoutingTableSerializer implements KadSerializer<RoutingTable>
|
||||||
{
|
{
|
||||||
@ -85,7 +85,7 @@ public class JsonRoutingTableSerializer implements KadSerializer<RoutingTable>
|
|||||||
{
|
{
|
||||||
}.getType();
|
}.getType();
|
||||||
List<Node> nodes = gson.fromJson(reader, collectionType);
|
List<Node> nodes = gson.fromJson(reader, collectionType);
|
||||||
tbl.initializeBuckets();
|
tbl.initialize();
|
||||||
|
|
||||||
for (Node n : nodes)
|
for (Node n : nodes)
|
||||||
{
|
{
|
||||||
|
@ -73,6 +73,6 @@ public class DHTContentImpl implements KadContent
|
|||||||
|
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return "DHTContentImpl[data=" + this.data + "]";
|
return "DHTContentImpl[{data=" + this.data + "{ {key:"+this.key + "}]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,21 +12,28 @@ import kademlia.node.NodeId;
|
|||||||
public class SaveStateTest
|
public class SaveStateTest
|
||||||
{
|
{
|
||||||
|
|
||||||
public static void main(String[] args)
|
public SaveStateTest()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
/* Setting up 2 Kad networks */
|
/* Setting up 2 Kad networks */
|
||||||
Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567467"), 7574);
|
Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567467"), 7529);
|
||||||
Kademlia kad2 = new Kademlia("Crystal", new NodeId("ASERTKJDHGVHERJHGFLK"), 7572);
|
Kademlia kad2 = new Kademlia("Crystal", new NodeId("ASERTKJDHGVHERJHGFLK"), 7532);
|
||||||
|
|
||||||
/* Connecting 2 to 1 */
|
/* Connecting 2 to 1 */
|
||||||
System.out.println("Connecting Kad 1 and Kad 2");
|
System.out.println("Connecting Kad 1 and Kad 2");
|
||||||
kad1.connect(kad2.getNode());
|
kad1.connect(kad2.getNode());
|
||||||
|
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
DHTContentImpl c = new DHTContentImpl(kad2.getOwnerId(), "Some Data");
|
||||||
|
System.out.println(c);
|
||||||
|
kad2.put(c);
|
||||||
|
}
|
||||||
|
|
||||||
System.out.println(kad1);
|
System.out.println(kad1);
|
||||||
System.out.println(kad2);
|
System.out.println(kad2);
|
||||||
|
|
||||||
/* Shutting down kad1 and restarting it */
|
/* Shutting down kad1 and restarting it */
|
||||||
System.out.println("\n\n\nShutting down Kad instance");
|
System.out.println("\n\n\nShutting down Kad instance");
|
||||||
kad1.shutdown();
|
kad1.shutdown();
|
||||||
@ -40,4 +47,9 @@ public class SaveStateTest
|
|||||||
e.printStackTrace();;
|
e.printStackTrace();;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
new SaveStateTest();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user