mirror of
https://github.com/ChronosX88/Influence-P2P.git
synced 2024-11-22 07:12:19 +00:00
Added BerkeleyDB as storage backend, added support of Kotlin lang, fixed some bugs
This commit is contained in:
parent
8a0e370936
commit
e7862b5b1c
@ -3,9 +3,6 @@
|
|||||||
<component name="GradleSettings">
|
<component name="GradleSettings">
|
||||||
<option name="linkedExternalProjectsSettings">
|
<option name="linkedExternalProjectsSettings">
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
<compositeConfiguration>
|
|
||||||
<compositeBuild compositeDefinitionSource="SCRIPT" />
|
|
||||||
</compositeConfiguration>
|
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android-extensions'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 28
|
compileSdkVersion 28
|
||||||
@ -52,4 +54,8 @@ dependencies {
|
|||||||
implementation group: 'org.springframework.security', name: 'spring-security-crypto', version: '3.1.0.RELEASE'
|
implementation group: 'org.springframework.security', name: 'spring-security-crypto', version: '3.1.0.RELEASE'
|
||||||
implementation 'de.hdodenhof:circleimageview:3.0.0'
|
implementation 'de.hdodenhof:circleimageview:3.0.0'
|
||||||
implementation group: 'org.objenesis', name: 'objenesis', version: '2.6'
|
implementation group: 'org.objenesis', name: 'objenesis', version: '2.6'
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
BIN
app/libs/je-android-5.0.104.jar
Normal file
BIN
app/libs/je-android-5.0.104.jar
Normal file
Binary file not shown.
@ -1,192 +0,0 @@
|
|||||||
package io.github.chronosx88.influence.helpers;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import net.tomp2p.connection.SignatureFactory;
|
|
||||||
import net.tomp2p.peers.Number160;
|
|
||||||
import net.tomp2p.storage.AlternativeCompositeByteBuf;
|
|
||||||
import net.tomp2p.storage.Data;
|
|
||||||
|
|
||||||
import org.mapdb.Serializer;
|
|
||||||
|
|
||||||
import java.io.DataInput;
|
|
||||||
import java.io.DataOutput;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.MappedByteBuffer;
|
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.SignatureException;
|
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import io.netty.buffer.Unpooled;
|
|
||||||
|
|
||||||
public class DataSerializerEx implements Serializer<Data>, Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1428836065493792295L;
|
|
||||||
//TODO: test the performance impact
|
|
||||||
private static final int MAX_SIZE = 10 * 1024;
|
|
||||||
|
|
||||||
private File path;
|
|
||||||
private SignatureFactory signatureFactory;
|
|
||||||
final private static KeyPairManager keyPairManager = new KeyPairManager();
|
|
||||||
|
|
||||||
public DataSerializerEx() { }
|
|
||||||
|
|
||||||
public DataSerializerEx(File path, SignatureFactory signatureFactory) {
|
|
||||||
this.path = path;
|
|
||||||
this.signatureFactory = signatureFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void serialize(DataOutput out, Data value) throws IOException {
|
|
||||||
if (value.length() > MAX_SIZE) {
|
|
||||||
// header, 1 means stored on disk in a file
|
|
||||||
out.writeByte(1);
|
|
||||||
serializeFile(out, value);
|
|
||||||
} else {
|
|
||||||
// header, 0 means stored on disk with MapDB
|
|
||||||
out.writeByte(0);
|
|
||||||
serializeMapDB(out, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void serializeMapDB(DataOutput out, Data value) throws IOException {
|
|
||||||
KeyPair keyPair = keyPairManager.getKeyPair("mainKeyForSign");
|
|
||||||
value.sign(keyPair);
|
|
||||||
AlternativeCompositeByteBuf acb = AlternativeCompositeByteBuf.compBuffer(AlternativeCompositeByteBuf.UNPOOLED_HEAP);
|
|
||||||
// store data to disk
|
|
||||||
// header first
|
|
||||||
value.encodeHeader(acb, signatureFactory);
|
|
||||||
write(out, acb.nioBuffers());
|
|
||||||
acb.skipBytes(acb.writerIndex());
|
|
||||||
// next data - no need to copy to another buffer, just take the data
|
|
||||||
// from memory
|
|
||||||
write(out, value.toByteBuffers());
|
|
||||||
// rest
|
|
||||||
try {
|
|
||||||
value.encodeDone(acb, signatureFactory);
|
|
||||||
write(out, acb.nioBuffers());
|
|
||||||
} catch (InvalidKeyException e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
} catch (SignatureException e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void serializeFile(DataOutput out, Data value) throws IOException, FileNotFoundException {
|
|
||||||
Number160 hash = value.hash();
|
|
||||||
// store file name
|
|
||||||
out.write(hash.toByteArray());
|
|
||||||
// store as external file, create path
|
|
||||||
RandomAccessFile file = null;
|
|
||||||
FileChannel rwChannel = null;
|
|
||||||
try {
|
|
||||||
file = new RandomAccessFile(new File(path, hash.toString()), "rw");
|
|
||||||
rwChannel = file.getChannel();
|
|
||||||
AlternativeCompositeByteBuf acb = AlternativeCompositeByteBuf.compBuffer(AlternativeCompositeByteBuf.UNPOOLED_HEAP);
|
|
||||||
// store data to disk
|
|
||||||
// header first
|
|
||||||
value.encodeHeader(acb, signatureFactory);
|
|
||||||
rwChannel.write(acb.nioBuffers());
|
|
||||||
// next data - no need to copy to another buffer, just take the
|
|
||||||
// data from memory
|
|
||||||
rwChannel.write(value.toByteBuffers());
|
|
||||||
// rest
|
|
||||||
try {
|
|
||||||
value.encodeDone(acb, signatureFactory);
|
|
||||||
rwChannel.write(acb.nioBuffers());
|
|
||||||
} catch (InvalidKeyException e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
} catch (SignatureException e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
|
|
||||||
if (rwChannel != null) {
|
|
||||||
rwChannel.close();
|
|
||||||
}
|
|
||||||
if (file != null) {
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void write(DataOutput out, ByteBuffer[] nioBuffers) throws IOException {
|
|
||||||
final int length = nioBuffers.length;
|
|
||||||
for(int i=0;i < length; i++) {
|
|
||||||
int remaining = nioBuffers[i].remaining();
|
|
||||||
if(nioBuffers[i].hasArray()) {
|
|
||||||
out.write(nioBuffers[i].array(), nioBuffers[i].arrayOffset(), remaining);
|
|
||||||
} else {
|
|
||||||
byte[] me = new byte[remaining];
|
|
||||||
nioBuffers[i].get(me);
|
|
||||||
out.write(me);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Data deserialize(DataInput in, int available) throws IOException {
|
|
||||||
int header = in.readByte();
|
|
||||||
if(header == 1) {
|
|
||||||
return deserializeFile(in);
|
|
||||||
} else if(header == 0) {
|
|
||||||
return deserializeMapDB(in);
|
|
||||||
} else {
|
|
||||||
//throw new IOException("unexpected header: " + header);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Data deserializeMapDB(DataInput in) throws IOException {
|
|
||||||
ByteBuf buf = Unpooled.buffer();
|
|
||||||
Data data = null;
|
|
||||||
while(data == null) {
|
|
||||||
buf.writeByte(in.readByte());
|
|
||||||
data = Data.decodeHeader(buf, signatureFactory);
|
|
||||||
}
|
|
||||||
int len = data.length();
|
|
||||||
byte me[] = new byte[len];
|
|
||||||
in.readFully(me);
|
|
||||||
buf = Unpooled.wrappedBuffer(me);
|
|
||||||
boolean retVal = data.decodeBuffer(buf);
|
|
||||||
if(!retVal) {
|
|
||||||
throw new IOException("data could not be read");
|
|
||||||
}
|
|
||||||
retVal = data.decodeDone(buf, signatureFactory);
|
|
||||||
if(!retVal) {
|
|
||||||
//throw new IOException("signature could not be read");
|
|
||||||
Log.e("DataSerializerEx", "# Signature could not be read!");
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Data deserializeFile(DataInput in) throws IOException, FileNotFoundException {
|
|
||||||
byte[] me = new byte[Number160.BYTE_ARRAY_SIZE];
|
|
||||||
in.readFully(me);
|
|
||||||
Number160 hash = new Number160(me);
|
|
||||||
RandomAccessFile file = new RandomAccessFile(new File(path, hash.toString()), "r");
|
|
||||||
FileChannel inChannel = file.getChannel();
|
|
||||||
MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
|
|
||||||
buffer.load();
|
|
||||||
ByteBuf buf = Unpooled.wrappedBuffer(buffer);
|
|
||||||
Data data = Data.decodeHeader(buf, signatureFactory);
|
|
||||||
data.decodeBuffer(buf);
|
|
||||||
data.decodeDone(buf, signatureFactory);
|
|
||||||
file.close();
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int fixedSize() {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,104 @@
|
|||||||
|
package io.github.chronosx88.influence.helpers
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
|
import com.sleepycat.bind.EntryBinding
|
||||||
|
import com.sleepycat.je.DatabaseEntry
|
||||||
|
|
||||||
|
import net.tomp2p.connection.SignatureFactory
|
||||||
|
import net.tomp2p.storage.AlternativeCompositeByteBuf
|
||||||
|
import net.tomp2p.storage.Data
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.io.Serializable
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.security.InvalidKeyException
|
||||||
|
import java.security.SignatureException
|
||||||
|
|
||||||
|
import io.netty.buffer.Unpooled
|
||||||
|
|
||||||
|
class DataSerializerEx(private val signatureFactory: SignatureFactory) : EntryBinding<Data>, Serializable {
|
||||||
|
private val LOG_TAG = "DataSerializerEx"
|
||||||
|
|
||||||
|
override fun entryToObject(databaseEntry: DatabaseEntry): Data? {
|
||||||
|
if (databaseEntry.data == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val inputStream = ByteArrayInputStream(databaseEntry.data)
|
||||||
|
var buf = Unpooled.buffer()
|
||||||
|
var data: Data? = null
|
||||||
|
while (data == null) {
|
||||||
|
buf.writeByte(inputStream.read())
|
||||||
|
data = Data.decodeHeader(buf, signatureFactory)
|
||||||
|
}
|
||||||
|
val len = data.length()
|
||||||
|
val me = ByteArray(len)
|
||||||
|
try {
|
||||||
|
inputStream.read(me)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = Unpooled.wrappedBuffer(me)
|
||||||
|
var retVal = data.decodeBuffer(buf)
|
||||||
|
if (!retVal) {
|
||||||
|
Log.e(LOG_TAG, "# ERROR: Data could not be deserialized!")
|
||||||
|
}
|
||||||
|
retVal = data.decodeDone(buf, signatureFactory)
|
||||||
|
if (!retVal) {
|
||||||
|
Log.e(LOG_TAG, "# ERROR: Signature could not be read!")
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun objectToEntry(data: Data, databaseEntry: DatabaseEntry) {
|
||||||
|
val forSigningKP = keyPairManager.getKeyPair("mainSigningKeyPair")
|
||||||
|
data.sign(forSigningKP)
|
||||||
|
val out = ByteArrayOutputStream()
|
||||||
|
val acb = AlternativeCompositeByteBuf.compBuffer(AlternativeCompositeByteBuf.UNPOOLED_HEAP)
|
||||||
|
try {
|
||||||
|
// header first
|
||||||
|
data.encodeHeader(acb, signatureFactory)
|
||||||
|
writeData(out, acb.nioBuffers())
|
||||||
|
acb.skipBytes(acb.writerIndex())
|
||||||
|
// next data - no need to copy to another buffer, just take the data
|
||||||
|
// from memory
|
||||||
|
writeData(out, data.toByteBuffers())
|
||||||
|
// rest
|
||||||
|
data.encodeDone(acb, signatureFactory)
|
||||||
|
writeData(out, acb.nioBuffers())
|
||||||
|
} catch (e: SignatureException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} catch (e: InvalidKeyException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
databaseEntry.data = out.toByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
private fun writeData(out: OutputStream, nioBuffers: Array<ByteBuffer>) {
|
||||||
|
val length = nioBuffers.size
|
||||||
|
for (i in 0 until length) {
|
||||||
|
val remaining = nioBuffers[i].remaining()
|
||||||
|
if (nioBuffers[i].hasArray()) {
|
||||||
|
out.write(nioBuffers[i].array(), nioBuffers[i].arrayOffset(), remaining)
|
||||||
|
} else {
|
||||||
|
val me = ByteArray(remaining)
|
||||||
|
nioBuffers[i].get(me)
|
||||||
|
out.write(me)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val serialVersionUID = 1428836065493792295L
|
||||||
|
private val keyPairManager = KeyPairManager()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,12 +10,14 @@ import java.security.NoSuchAlgorithmException;
|
|||||||
|
|
||||||
public class KeyPairManager {
|
public class KeyPairManager {
|
||||||
private File keyPairDir;
|
private File keyPairDir;
|
||||||
|
private Serializer<KeyPair> serializer;
|
||||||
|
|
||||||
public KeyPairManager() {
|
public KeyPairManager() {
|
||||||
this.keyPairDir = new File(AppHelper.getContext().getFilesDir().getAbsoluteFile(), "keyPairs");
|
this.keyPairDir = new File(AppHelper.getContext().getFilesDir().getAbsoluteFile(), "keyPairs");
|
||||||
if(!this.keyPairDir.exists()) {
|
if(!this.keyPairDir.exists()) {
|
||||||
this.keyPairDir.mkdir();
|
this.keyPairDir.mkdir();
|
||||||
}
|
}
|
||||||
|
this.serializer = new Serializer<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyPair openMainKeyPair() {
|
public KeyPair openMainKeyPair() {
|
||||||
@ -39,7 +41,7 @@ public class KeyPairManager {
|
|||||||
byte[] serializedKeyPair = new byte[(int) keyPairFile.length()];
|
byte[] serializedKeyPair = new byte[(int) keyPairFile.length()];
|
||||||
inputStream.read(serializedKeyPair);
|
inputStream.read(serializedKeyPair);
|
||||||
inputStream.close();
|
inputStream.close();
|
||||||
keyPair = (KeyPair) Serializer.deserialize(serializedKeyPair);
|
keyPair = serializer.deserialize(serializedKeyPair);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -52,7 +54,7 @@ public class KeyPairManager {
|
|||||||
keyPairFile.createNewFile();
|
keyPairFile.createNewFile();
|
||||||
keyPair = KeyPairGenerator.getInstance("DSA").generateKeyPair();
|
keyPair = KeyPairGenerator.getInstance("DSA").generateKeyPair();
|
||||||
FileOutputStream outputStream = new FileOutputStream(keyPairFile);
|
FileOutputStream outputStream = new FileOutputStream(keyPairFile);
|
||||||
outputStream.write(Serializer.serialize(keyPair));
|
outputStream.write(serializer.serialize(keyPair));
|
||||||
outputStream.close();
|
outputStream.close();
|
||||||
} catch (IOException | NoSuchAlgorithmException e) {
|
} catch (IOException | NoSuchAlgorithmException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -65,7 +67,7 @@ public class KeyPairManager {
|
|||||||
if(!keyPairFile.exists()) {
|
if(!keyPairFile.exists()) {
|
||||||
try {
|
try {
|
||||||
FileOutputStream outputStream = new FileOutputStream(keyPairFile);
|
FileOutputStream outputStream = new FileOutputStream(keyPairFile);
|
||||||
outputStream.write(Serializer.serialize(keyPair));
|
outputStream.write(serializer.serialize(keyPair));
|
||||||
outputStream.close();
|
outputStream.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -54,7 +54,7 @@ public class P2PUtils {
|
|||||||
.all()
|
.all()
|
||||||
.start()
|
.start()
|
||||||
.awaitUninterruptibly();
|
.awaitUninterruptibly();
|
||||||
if(!futureGet.isEmpty()) {
|
if(futureGet != null && !futureGet.isEmpty()) {
|
||||||
return futureGet.dataMap();
|
return futureGet.dataMap();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
package io.github.chronosx88.influence.helpers;
|
|
||||||
|
|
||||||
import org.springframework.security.crypto.codec.Base64;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
public class PrepareData {
|
|
||||||
public static <T> String prepareToStore(T object) {
|
|
||||||
if(object instanceof Serializable) {
|
|
||||||
byte[] serializedObject = Serializer.serialize(object);
|
|
||||||
return new String(Base64.encode(serializedObject));
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object prepareFromStore(String object) {
|
|
||||||
return Serializer.deserialize(Base64.decode(object.getBytes()));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +1,20 @@
|
|||||||
package io.github.chronosx88.influence.helpers;
|
package io.github.chronosx88.influence.helpers;
|
||||||
|
|
||||||
|
import com.sleepycat.bind.EntryBinding;
|
||||||
|
import com.sleepycat.je.DatabaseEntry;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
|
|
||||||
public class Serializer {
|
public class Serializer<T> implements EntryBinding<T> {
|
||||||
public static byte[] serialize(Object object) {
|
public byte[] serialize(T object) {
|
||||||
ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
|
ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
|
||||||
try {
|
try {
|
||||||
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArray);
|
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArray);
|
||||||
objectOutputStream.writeObject(object);;
|
objectOutputStream.writeObject(object);
|
||||||
objectOutputStream.close();
|
objectOutputStream.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -19,19 +22,7 @@ public class Serializer {
|
|||||||
return byteArray.toByteArray();
|
return byteArray.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object deserialize(String serializedObject) {
|
public T deserialize(byte[] serializedObject) {
|
||||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(serializedObject.getBytes());
|
|
||||||
Object object = null;
|
|
||||||
try {
|
|
||||||
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
|
|
||||||
object = objectInputStream.readObject();
|
|
||||||
} catch (ClassNotFoundException | IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object deserialize(byte[] serializedObject) {
|
|
||||||
if(serializedObject == null)
|
if(serializedObject == null)
|
||||||
return null;
|
return null;
|
||||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(serializedObject);
|
ByteArrayInputStream inputStream = new ByteArrayInputStream(serializedObject);
|
||||||
@ -42,6 +33,16 @@ public class Serializer {
|
|||||||
} catch (ClassNotFoundException | IOException e) {
|
} catch (ClassNotFoundException | IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
return object;
|
return (T) object;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T entryToObject(DatabaseEntry databaseEntry) {
|
||||||
|
return deserialize(databaseEntry.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void objectToEntry(T object, DatabaseEntry databaseEntry) {
|
||||||
|
databaseEntry.setData(serialize(object));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,262 @@
|
|||||||
|
package io.github.chronosx88.influence.helpers
|
||||||
|
|
||||||
|
import com.sleepycat.collections.StoredSortedMap
|
||||||
|
import com.sleepycat.je.Database
|
||||||
|
import com.sleepycat.je.DatabaseConfig
|
||||||
|
import com.sleepycat.je.Environment
|
||||||
|
import com.sleepycat.je.EnvironmentConfig
|
||||||
|
import net.tomp2p.connection.SignatureFactory
|
||||||
|
import net.tomp2p.dht.Storage
|
||||||
|
import net.tomp2p.peers.Number160
|
||||||
|
import net.tomp2p.peers.Number320
|
||||||
|
import net.tomp2p.peers.Number480
|
||||||
|
import net.tomp2p.peers.Number640
|
||||||
|
import net.tomp2p.storage.Data
|
||||||
|
import java.io.File
|
||||||
|
import java.security.PublicKey
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
|
||||||
|
class StorageBerkeleyDB(peerId: Number160, path : File, signatureFactory: SignatureFactory) : Storage {
|
||||||
|
// Core
|
||||||
|
private val dataMap: StoredSortedMap<Number640, Data>
|
||||||
|
// Maintenance
|
||||||
|
private val timeoutMap: StoredSortedMap<Number640, Long>
|
||||||
|
private val timeoutMapRev: StoredSortedMap<Long, Set<Number640>>
|
||||||
|
// Protection
|
||||||
|
private val protectedDomainMap: StoredSortedMap<Number320, PublicKey>
|
||||||
|
private val protectedEntryMap: StoredSortedMap<Number480, PublicKey>
|
||||||
|
// Responsibility
|
||||||
|
private val responsibilityMap: StoredSortedMap<Number160, Number160>
|
||||||
|
private val responsibilityMapRev: StoredSortedMap<Number160, Set<Number160>>
|
||||||
|
|
||||||
|
private val dataMapDB: Database
|
||||||
|
private val timeoutMapDB: Database
|
||||||
|
private val timeoutMapRevDB: Database
|
||||||
|
private val protectedDomainMapDB: Database
|
||||||
|
private val protectedEntryMapDB: Database
|
||||||
|
private val responsibilityMapDB: Database
|
||||||
|
private val responsibilityMapRevDB: Database
|
||||||
|
|
||||||
|
|
||||||
|
private val storageCheckIntervalMillis: Int
|
||||||
|
private val dbEnvironment: Environment
|
||||||
|
|
||||||
|
init {
|
||||||
|
val envConfig = EnvironmentConfig()
|
||||||
|
envConfig.allowCreate = true
|
||||||
|
dbEnvironment = Environment(path, envConfig)
|
||||||
|
val dbConfig = DatabaseConfig()
|
||||||
|
dbConfig.allowCreate = true
|
||||||
|
|
||||||
|
dataMapDB = dbEnvironment.openDatabase(null, "dataMap_$peerId", dbConfig)
|
||||||
|
timeoutMapDB = dbEnvironment.openDatabase(null, "timeoutMap_$peerId", dbConfig)
|
||||||
|
timeoutMapRevDB = dbEnvironment.openDatabase(null, "timeoutMapRev_$peerId", dbConfig)
|
||||||
|
protectedDomainMapDB = dbEnvironment.openDatabase(null, "protectedDomainMap_$peerId", dbConfig)
|
||||||
|
protectedEntryMapDB = dbEnvironment.openDatabase(null, "protectedEntryMap_$peerId", dbConfig)
|
||||||
|
responsibilityMapDB = dbEnvironment.openDatabase(null, "responsibilityMap_$peerId", dbConfig)
|
||||||
|
responsibilityMapRevDB = dbEnvironment.openDatabase(null, "responsibilityMapRev_$peerId", dbConfig)
|
||||||
|
|
||||||
|
storageCheckIntervalMillis = 60 * 1000
|
||||||
|
|
||||||
|
dataMap = StoredSortedMap(dataMapDB, Serializer<Number640>(), DataSerializerEx(signatureFactory), true)
|
||||||
|
timeoutMap = StoredSortedMap(timeoutMapDB, Serializer<Number640>(), Serializer<Long>(), true)
|
||||||
|
timeoutMapRev = StoredSortedMap(timeoutMapRevDB, Serializer<Long>(), Serializer<Set<Number640>>(), true)
|
||||||
|
protectedDomainMap = StoredSortedMap(protectedDomainMapDB, Serializer<Number320>(), Serializer<PublicKey>(), true)
|
||||||
|
protectedEntryMap = StoredSortedMap(protectedEntryMapDB, Serializer<Number480>(), Serializer<PublicKey>(), true)
|
||||||
|
responsibilityMap = StoredSortedMap(responsibilityMapDB, Serializer<Number160>(), Serializer<Number160>(), true)
|
||||||
|
responsibilityMapRev = StoredSortedMap(responsibilityMapRevDB, Serializer<Number160>(), Serializer<Set<Number160>>(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun contains(key: Number640?): Boolean {
|
||||||
|
return dataMap.containsKey(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun contains(from: Number640?, to: Number640?): Int {
|
||||||
|
return dataMap.subMap(from, true, to, true).size
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findContentForResponsiblePeerID(peerID: Number160?): MutableSet<Number160> {
|
||||||
|
return responsibilityMapRev[peerID] as MutableSet<Number160>
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findPeerIDsForResponsibleContent(locationKey: Number160?): Number160? {
|
||||||
|
return responsibilityMap[locationKey]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun put(key: Number640?, value: Data?): Data? {
|
||||||
|
return dataMap.put(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(key: Number640?): Data? {
|
||||||
|
return dataMap[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove(key: Number640?, returnData: Boolean): Data? {
|
||||||
|
return dataMap.remove(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove(from: Number640?, to: Number640?): NavigableMap<Number640, Data> {
|
||||||
|
val tmp = dataMap.subMap(from, true, to, true)
|
||||||
|
val retVal = TreeMap<Number640, Data>()
|
||||||
|
for(entry : Map.Entry<Number640, Data> in tmp.entries) {
|
||||||
|
retVal[entry.key] = entry.value
|
||||||
|
}
|
||||||
|
tmp.clear()
|
||||||
|
return retVal
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addTimeout(key: Number640, expiration: Long) {
|
||||||
|
val oldExpiration = timeoutMap.put(key, expiration)
|
||||||
|
putIfAbsent2(expiration, key)
|
||||||
|
if (oldExpiration == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
removeRevTimeout(key, oldExpiration)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun putIfAbsent2(expiration: Long, key: Number640) {
|
||||||
|
var timeouts = timeoutMapRev[expiration]
|
||||||
|
//var timeouts : MutableSet<Number640> = timeoutMapRev[expiration] as MutableSet<Number640>
|
||||||
|
if (timeouts == null) {
|
||||||
|
timeouts = Collections.newSetFromMap(ConcurrentHashMap())
|
||||||
|
}
|
||||||
|
(timeouts as MutableSet).add(key)
|
||||||
|
timeoutMapRev[expiration] = timeouts
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeRevTimeout(key: Number640, expiration: Long?) {
|
||||||
|
val tmp = timeoutMapRev[expiration] as MutableSet<Number640>
|
||||||
|
if (tmp != null) {
|
||||||
|
tmp.remove(key)
|
||||||
|
if (tmp.isEmpty()) {
|
||||||
|
timeoutMapRev.remove(expiration)
|
||||||
|
} else {
|
||||||
|
timeoutMapRev[expiration!!] = tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateResponsibilities(locationKey: Number160, peerId: Number160?): Boolean {
|
||||||
|
val oldPeerID = responsibilityMap.put(locationKey, peerId)
|
||||||
|
val hasChanged: Boolean
|
||||||
|
if (oldPeerID != null) {
|
||||||
|
if (oldPeerID == peerId) {
|
||||||
|
hasChanged = false
|
||||||
|
} else {
|
||||||
|
removeRevResponsibility(oldPeerID, locationKey)
|
||||||
|
hasChanged = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hasChanged = true
|
||||||
|
}
|
||||||
|
var contentIDs: MutableSet<Number160>? = responsibilityMapRev[peerId] as MutableSet
|
||||||
|
if (contentIDs == null) {
|
||||||
|
contentIDs = HashSet()
|
||||||
|
}
|
||||||
|
contentIDs.add(locationKey)
|
||||||
|
responsibilityMapRev[peerId] = contentIDs
|
||||||
|
return hasChanged
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeRevResponsibility(peerId: Number160, locationKey: Number160) {
|
||||||
|
val contentIDs = responsibilityMapRev[peerId] as MutableSet
|
||||||
|
if (contentIDs != null) {
|
||||||
|
contentIDs.remove(locationKey)
|
||||||
|
if (contentIDs.isEmpty()) {
|
||||||
|
responsibilityMapRev.remove(peerId)
|
||||||
|
} else {
|
||||||
|
responsibilityMapRev[peerId] = contentIDs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun protectDomain(key: Number320?, publicKey: PublicKey?): Boolean {
|
||||||
|
protectedDomainMap[key] = publicKey
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun storageCheckIntervalMillis(): Int {
|
||||||
|
return storageCheckIntervalMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isDomainProtectedByOthers(key: Number320?, publicKey: PublicKey?): Boolean {
|
||||||
|
val other = protectedDomainMap[key] ?: return false
|
||||||
|
return other != publicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeTimeout(key: Number640) {
|
||||||
|
val expiration = timeoutMap.remove(key) ?: return
|
||||||
|
removeRevTimeout(key, expiration)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeResponsibility(locationKey: Number160) {
|
||||||
|
val peerId = responsibilityMap.remove(locationKey)
|
||||||
|
if (peerId != null) {
|
||||||
|
removeRevResponsibility(peerId, locationKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun protectEntry(key: Number480?, publicKey: PublicKey?): Boolean {
|
||||||
|
protectedEntryMap[key] = publicKey
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun map(): NavigableMap<Number640, Data> {
|
||||||
|
val retVal = TreeMap<Number640, Data>()
|
||||||
|
for ((key, value) in dataMap) {
|
||||||
|
retVal[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isEntryProtectedByOthers(key: Number480?, publicKey: PublicKey?): Boolean {
|
||||||
|
val other = protectedEntryMap[key] ?: return false
|
||||||
|
return other != publicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun subMap(from: Number640?, to: Number640?, limit: Int, ascending: Boolean): NavigableMap<Number640, Data> {
|
||||||
|
val tmp = dataMap.subMap(from, true, to, true)
|
||||||
|
val descendingMap = TreeMap<Number640, Data>(tmp).descendingMap()
|
||||||
|
val retVal = TreeMap<Number640, Data>()
|
||||||
|
if (limit < 0) {
|
||||||
|
for ((key, value) in if (ascending) tmp else descendingMap) {
|
||||||
|
retVal[key] = value
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val limit1 = Math.min(limit, tmp.size)
|
||||||
|
val iterator = if (ascending)
|
||||||
|
tmp.entries.iterator()
|
||||||
|
else
|
||||||
|
descendingMap.entries.iterator()
|
||||||
|
var i = 0
|
||||||
|
while (iterator.hasNext() && i < limit1) {
|
||||||
|
val entry = iterator.next()
|
||||||
|
retVal[entry.key] = entry.value
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun subMapTimeout(to: Long): MutableCollection<Number640> {
|
||||||
|
val tmp = timeoutMapRev.subMap(0L, to)
|
||||||
|
val toRemove = ArrayList<Number640>()
|
||||||
|
for (set in tmp.values) {
|
||||||
|
toRemove.addAll(set)
|
||||||
|
}
|
||||||
|
return toRemove
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
dataMapDB.close()
|
||||||
|
timeoutMapDB.close()
|
||||||
|
timeoutMapRevDB.close()
|
||||||
|
protectedDomainMapDB.close()
|
||||||
|
protectedEntryMapDB.close()
|
||||||
|
responsibilityMapDB.close()
|
||||||
|
responsibilityMapRevDB.close()
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
package io.github.chronosx88.influence.helpers;
|
package io.github.chronosx88.influence.helpers;
|
||||||
|
/*
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import net.tomp2p.connection.DSASignatureFactory;
|
import net.tomp2p.connection.DSASignatureFactory;
|
||||||
@ -391,3 +391,4 @@ public class StorageMVStore implements Storage {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
@ -1,5 +1,5 @@
|
|||||||
package io.github.chronosx88.influence.helpers;
|
package io.github.chronosx88.influence.helpers;
|
||||||
|
/*
|
||||||
import net.tomp2p.connection.SignatureFactory;
|
import net.tomp2p.connection.SignatureFactory;
|
||||||
import net.tomp2p.dht.Storage;
|
import net.tomp2p.dht.Storage;
|
||||||
import net.tomp2p.peers.Number160;
|
import net.tomp2p.peers.Number160;
|
||||||
@ -96,27 +96,6 @@ public class StorageMapDB implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public NavigableMap<Number640, Data> remove(Number640 from, Number640 to) {
|
public NavigableMap<Number640, Data> remove(Number640 from, Number640 to) {
|
||||||
NavigableMap<Number640, Data> tmp = dataMap.subMap(from, true, to, true);
|
NavigableMap<Number640, Data> tmp = dataMap.subMap(from, true, to, true);
|
||||||
|
|
||||||
// new TreeMap<Number640, Data>(tmp); is not possible as this may lead to no such element exception:
|
|
||||||
//
|
|
||||||
// java.util.NoSuchElementException: null
|
|
||||||
// at java.util.concurrent.ConcurrentSkipListMap$SubMap$SubMapIter.advance(ConcurrentSkipListMap.java:3030) ~[na:1.7.0_60]
|
|
||||||
// at java.util.concurrent.ConcurrentSkipListMap$SubMap$SubMapEntryIterator.next(ConcurrentSkipListMap.java:3100) ~[na:1.7.0_60]
|
|
||||||
// at java.util.concurrent.ConcurrentSkipListMap$SubMap$SubMapEntryIterator.next(ConcurrentSkipListMap.java:3096) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2394) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2344) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.<init>(TreeMap.java:195) ~[na:1.7.0_60]
|
|
||||||
// at net.tomp2p.dht.StorageMemory.subMap(StorageMemory.java:119) ~[classes/:na]
|
|
||||||
//
|
|
||||||
// the reason is that the size in TreeMap.buildFromSorted is stored beforehand, then iteratated. If the size changes,
|
|
||||||
// then you will call next() that returns null and an exception is thrown.
|
|
||||||
final NavigableMap<Number640, Data> retVal = new TreeMap<Number640, Data>();
|
final NavigableMap<Number640, Data> retVal = new TreeMap<Number640, Data>();
|
||||||
for(final Map.Entry<Number640, Data> entry:tmp.entrySet()) {
|
for(final Map.Entry<Number640, Data> entry:tmp.entrySet()) {
|
||||||
retVal.put(entry.getKey(), entry.getValue());
|
retVal.put(entry.getKey(), entry.getValue());
|
||||||
@ -132,28 +111,6 @@ public class StorageMapDB implements Storage {
|
|||||||
NavigableMap<Number640, Data> tmp = dataMap.subMap(from, true, to, true);
|
NavigableMap<Number640, Data> tmp = dataMap.subMap(from, true, to, true);
|
||||||
final NavigableMap<Number640, Data> retVal = new TreeMap<Number640, Data>();
|
final NavigableMap<Number640, Data> retVal = new TreeMap<Number640, Data>();
|
||||||
if (limit < 0) {
|
if (limit < 0) {
|
||||||
|
|
||||||
// new TreeMap<Number640, Data>(tmp); is not possible as this may lead to no such element exception:
|
|
||||||
//
|
|
||||||
// java.util.NoSuchElementException: null
|
|
||||||
// at java.util.concurrent.ConcurrentSkipListMap$SubMap$SubMapIter.advance(ConcurrentSkipListMap.java:3030) ~[na:1.7.0_60]
|
|
||||||
// at java.util.concurrent.ConcurrentSkipListMap$SubMap$SubMapEntryIterator.next(ConcurrentSkipListMap.java:3100) ~[na:1.7.0_60]
|
|
||||||
// at java.util.concurrent.ConcurrentSkipListMap$SubMap$SubMapEntryIterator.next(ConcurrentSkipListMap.java:3096) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2394) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2344) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.<init>(TreeMap.java:195) ~[na:1.7.0_60]
|
|
||||||
// at net.tomp2p.dht.StorageMemory.subMap(StorageMemory.java:119) ~[classes/:na]
|
|
||||||
//
|
|
||||||
// the reason is that the size in TreeMap.buildFromSorted is stored beforehand, then iteratated. If the size changes,
|
|
||||||
// then you will call next() that returns null and an exception is thrown.
|
|
||||||
|
|
||||||
for(final Map.Entry<Number640, Data> entry:(ascending ? tmp : tmp.descendingMap()).entrySet()) {
|
for(final Map.Entry<Number640, Data> entry:(ascending ? tmp : tmp.descendingMap()).entrySet()) {
|
||||||
retVal.put(entry.getKey(), entry.getValue());
|
retVal.put(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
@ -171,27 +128,6 @@ public class StorageMapDB implements Storage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NavigableMap<Number640, Data> map() {
|
public NavigableMap<Number640, Data> map() {
|
||||||
|
|
||||||
// new TreeMap<Number640, Data>(dataMap); is not possible as this may lead to no such element exception:
|
|
||||||
//
|
|
||||||
// java.util.NoSuchElementException: null
|
|
||||||
// at java.util.concurrent.ConcurrentSkipListMap$SubMap$SubMapIter.advance(ConcurrentSkipListMap.java:3030) ~[na:1.7.0_60]
|
|
||||||
// at java.util.concurrent.ConcurrentSkipListMap$SubMap$SubMapEntryIterator.next(ConcurrentSkipListMap.java:3100) ~[na:1.7.0_60]
|
|
||||||
// at java.util.concurrent.ConcurrentSkipListMap$SubMap$SubMapEntryIterator.next(ConcurrentSkipListMap.java:3096) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2394) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2418) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.buildFromSorted(TreeMap.java:2344) ~[na:1.7.0_60]
|
|
||||||
// at java.util.TreeMap.<init>(TreeMap.java:195) ~[na:1.7.0_60]
|
|
||||||
// at net.tomp2p.dht.StorageMemory.subMap(StorageMemory.java:119) ~[classes/:na]
|
|
||||||
//
|
|
||||||
// the reason is that the size in TreeMap.buildFromSorted is stored beforehand, then iteratated. If the size changes,
|
|
||||||
// then you will call next() that returns null and an exception is thrown.
|
|
||||||
final NavigableMap<Number640, Data> retVal = new TreeMap<Number640, Data>();
|
final NavigableMap<Number640, Data> retVal = new TreeMap<Number640, Data>();
|
||||||
for(final Map.Entry<Number640, Data> entry:dataMap.entrySet()) {
|
for(final Map.Entry<Number640, Data> entry:dataMap.entrySet()) {
|
||||||
retVal.put(entry.getKey(), entry.getValue());
|
retVal.put(entry.getKey(), entry.getValue());
|
||||||
@ -354,3 +290,4 @@ public class StorageMapDB implements Storage {
|
|||||||
return storageCheckIntervalMillis;
|
return storageCheckIntervalMillis;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
@ -148,8 +148,8 @@ public class ChatLogic implements IChatLogicContract {
|
|||||||
if(messages.size() > 10) {
|
if(messages.size() > 10) {
|
||||||
String messageID = UUID.randomUUID().toString();
|
String messageID = UUID.randomUUID().toString();
|
||||||
try {
|
try {
|
||||||
chatEntity.chunkCursor += 1;
|
P2PUtils.put(chatEntity.chatID + "_messages" + chunkID, messageID, new Data(gson.toJson(new NextChunkReference(messageID, AppHelper.getPeerID(), AppHelper.getPeerID(), System.currentTimeMillis(), chatEntity.chunkCursor+1))));
|
||||||
P2PUtils.put(chatID + "_messages" + chatEntity.chunkCursor, messageID, new Data(gson.toJson(new NextChunkReference(messageID, AppHelper.getPeerID(), AppHelper.getPeerID(), System.currentTimeMillis(), chatEntity.chunkCursor))));
|
P2PUtils.put(chatEntity.chatID + "_newMessage", null, new Data(messageID));
|
||||||
LocalDBWrapper.updateChatEntity(chatEntity);
|
LocalDBWrapper.updateChatEntity(chatEntity);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -10,7 +10,6 @@ import com.google.gson.JsonObject;
|
|||||||
import net.tomp2p.connection.DSASignatureFactory;
|
import net.tomp2p.connection.DSASignatureFactory;
|
||||||
import net.tomp2p.dht.PeerBuilderDHT;
|
import net.tomp2p.dht.PeerBuilderDHT;
|
||||||
import net.tomp2p.dht.PeerDHT;
|
import net.tomp2p.dht.PeerDHT;
|
||||||
import net.tomp2p.dht.StorageMemory;
|
|
||||||
import net.tomp2p.futures.FutureBootstrap;
|
import net.tomp2p.futures.FutureBootstrap;
|
||||||
import net.tomp2p.futures.FutureDiscover;
|
import net.tomp2p.futures.FutureDiscover;
|
||||||
import net.tomp2p.nat.FutureRelayNAT;
|
import net.tomp2p.nat.FutureRelayNAT;
|
||||||
@ -43,7 +42,7 @@ import io.github.chronosx88.influence.helpers.JVMShutdownHook;
|
|||||||
import io.github.chronosx88.influence.helpers.KeyPairManager;
|
import io.github.chronosx88.influence.helpers.KeyPairManager;
|
||||||
import io.github.chronosx88.influence.helpers.NetworkHandler;
|
import io.github.chronosx88.influence.helpers.NetworkHandler;
|
||||||
import io.github.chronosx88.influence.helpers.P2PUtils;
|
import io.github.chronosx88.influence.helpers.P2PUtils;
|
||||||
import io.github.chronosx88.influence.helpers.StorageMapDB;
|
import io.github.chronosx88.influence.helpers.StorageBerkeleyDB;
|
||||||
import io.github.chronosx88.influence.helpers.actions.UIActions;
|
import io.github.chronosx88.influence.helpers.actions.UIActions;
|
||||||
import io.github.chronosx88.influence.models.PublicUserProfile;
|
import io.github.chronosx88.influence.models.PublicUserProfile;
|
||||||
|
|
||||||
@ -60,6 +59,7 @@ public class MainLogic implements IMainLogicContract {
|
|||||||
private AutoReplication replication;
|
private AutoReplication replication;
|
||||||
private KeyPairManager keyPairManager;
|
private KeyPairManager keyPairManager;
|
||||||
private Thread checkNewChatsThread = null;
|
private Thread checkNewChatsThread = null;
|
||||||
|
private StorageBerkeleyDB storage;
|
||||||
|
|
||||||
public MainLogic() {
|
public MainLogic() {
|
||||||
this.context = AppHelper.getContext();
|
this.context = AppHelper.getContext();
|
||||||
@ -83,15 +83,16 @@ public class MainLogic implements IMainLogicContract {
|
|||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
StorageMapDB storageMapDB = new StorageMapDB(peerID, context.getFilesDir(), new DSASignatureFactory());
|
StorageBerkeleyDB storageBerkeleyDB = new StorageBerkeleyDB(peerID, context.getFilesDir(), new DSASignatureFactory());
|
||||||
|
this.storage = storageBerkeleyDB;
|
||||||
peerDHT = new PeerBuilderDHT(
|
peerDHT = new PeerBuilderDHT(
|
||||||
new PeerBuilder(peerID)
|
new PeerBuilder(peerID)
|
||||||
.ports(7243)
|
.ports(7243)
|
||||||
.start()
|
.start()
|
||||||
)
|
)
|
||||||
.storage(storageMapDB)
|
.storage(storageBerkeleyDB)
|
||||||
.start();
|
.start();
|
||||||
Runtime.getRuntime().addShutdownHook(new JVMShutdownHook(storageMapDB));
|
Runtime.getRuntime().addShutdownHook(new JVMShutdownHook(storageBerkeleyDB));
|
||||||
try {
|
try {
|
||||||
String bootstrapIP = this.preferences.getString("bootstrapAddress", null);
|
String bootstrapIP = this.preferences.getString("bootstrapAddress", null);
|
||||||
if(bootstrapIP == null) {
|
if(bootstrapIP == null) {
|
||||||
@ -227,7 +228,8 @@ public class MainLogic implements IMainLogicContract {
|
|||||||
replication.shutdown().start();
|
replication.shutdown().start();
|
||||||
}
|
}
|
||||||
peerDHT.peer().announceShutdown().start().awaitUninterruptibly();
|
peerDHT.peer().announceShutdown().start().awaitUninterruptibly();
|
||||||
peerDHT.peer().shutdown();
|
peerDHT.peer().shutdown().awaitUninterruptibly();
|
||||||
|
storage.close();
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
|
ext.kotlin_version = '1.3.21'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
@ -10,7 +11,8 @@ buildscript {
|
|||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.3.2'
|
classpath 'com.android.tools.build:gradle:3.3.2'
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user