mirror of
https://github.com/ChronosX88/Influence-P2P.git
synced 2024-11-24 16:22:17 +00:00
[WIP] Changed storage backend to MapDB
This commit is contained in:
parent
046abcb465
commit
ad357c779e
@ -40,9 +40,9 @@ dependencies {
|
|||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3'
|
||||||
implementation "androidx.room:room-runtime:2.1.0-alpha04"
|
implementation "androidx.room:room-runtime:2.1.0-alpha04"
|
||||||
annotationProcessor "androidx.room:room-compiler:2.1.0-alpha04"
|
annotationProcessor "androidx.room:room-compiler:2.1.0-alpha04"
|
||||||
implementation('net.tomp2p:tomp2p-all:5.0-Beta8') //{
|
implementation('net.tomp2p:tomp2p-all:5.0-Beta8') {
|
||||||
//exclude group: 'org.mapdb', module: 'mapdb'
|
exclude group: 'net.tomp2p', module: 'tomp2p-storage'
|
||||||
//}
|
}
|
||||||
implementation 'org.slf4j:slf4j-log4j12:1.7.26'
|
implementation 'org.slf4j:slf4j-log4j12:1.7.26'
|
||||||
implementation group: 'com.h2database', name: 'h2-mvstore', version: '1.4.197'
|
implementation group: 'com.h2database', name: 'h2-mvstore', version: '1.4.197'
|
||||||
implementation 'com.google.android.material:material:1.1.0-alpha04'
|
implementation 'com.google.android.material:material:1.1.0-alpha04'
|
||||||
@ -50,4 +50,5 @@ dependencies {
|
|||||||
implementation 'com.google.code.gson:gson:2.8.5'
|
implementation 'com.google.code.gson:gson:2.8.5'
|
||||||
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 'org.mapdb:mapdb:2.0-beta13'
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ public class Converter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
public static String fromArrayLisr(ArrayList<String> list) {
|
public static String fromArrayList(ArrayList<String> list) {
|
||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
return gson.toJson(list);
|
return gson.toJson(list);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,194 @@
|
|||||||
|
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.DataIO;
|
||||||
|
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 extends Serializer<Data> implements 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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!");
|
||||||
|
}
|
||||||
|
DataIO.DataInputByteArray di = (DataIO.DataInputByteArray) in;
|
||||||
|
di.setPos(di.internalByteArray().length);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,11 @@
|
|||||||
package io.github.chronosx88.influence.helpers;
|
package io.github.chronosx88.influence.helpers;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import net.tomp2p.dht.Storage;
|
import net.tomp2p.dht.Storage;
|
||||||
|
|
||||||
public class JVMShutdownHook extends Thread {
|
public class JVMShutdownHook extends Thread {
|
||||||
|
|
||||||
Storage storage;
|
Storage storage;
|
||||||
|
|
||||||
public JVMShutdownHook(Storage storage) {
|
public JVMShutdownHook(Storage storage) {
|
||||||
@ -12,6 +15,9 @@ public class JVMShutdownHook extends Thread {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
super.run();
|
super.run();
|
||||||
|
Log.d("JVMShutdownHook", "# Closing storage...");
|
||||||
storage.close();
|
storage.close();
|
||||||
|
Log.d("JVMShutdownHook", "# Storage is closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
package io.github.chronosx88.influence.helpers;
|
package io.github.chronosx88.influence.helpers;
|
||||||
|
|
||||||
|
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 org.mapdb.DB;
|
||||||
|
import org.mapdb.DBMaker;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -15,18 +26,6 @@ import java.util.TreeMap;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentNavigableMap;
|
import java.util.concurrent.ConcurrentNavigableMap;
|
||||||
|
|
||||||
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 net.tomp2p.storage.DataSerializer;
|
|
||||||
|
|
||||||
import org.mapdb.DB;
|
|
||||||
import org.mapdb.DBMaker;
|
|
||||||
|
|
||||||
public class StorageMapDB implements Storage {
|
public class StorageMapDB implements Storage {
|
||||||
// Core
|
// Core
|
||||||
final private NavigableMap<Number640, Data> dataMap;
|
final private NavigableMap<Number640, Data> dataMap;
|
||||||
@ -47,7 +46,7 @@ public class StorageMapDB implements Storage {
|
|||||||
//for full control
|
//for full control
|
||||||
public StorageMapDB(DB db, Number160 peerId, File path, SignatureFactory signatureFactory, int storageCheckIntervalMillis) {
|
public StorageMapDB(DB db, Number160 peerId, File path, SignatureFactory signatureFactory, int storageCheckIntervalMillis) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
DataSerializer dataSerializer = new DataSerializer(path, signatureFactory);
|
DataSerializerEx dataSerializer = new DataSerializerEx(path, signatureFactory);
|
||||||
this.dataMap = db.createTreeMap("dataMap_" + peerId.toString()).valueSerializer(dataSerializer).makeOrGet();
|
this.dataMap = db.createTreeMap("dataMap_" + peerId.toString()).valueSerializer(dataSerializer).makeOrGet();
|
||||||
this.timeoutMap = db.createTreeMap("timeoutMap_" + peerId.toString()).makeOrGet();
|
this.timeoutMap = db.createTreeMap("timeoutMap_" + peerId.toString()).makeOrGet();
|
||||||
this.timeoutMapRev = db.createTreeMap("timeoutMapRev_" + peerId.toString()).makeOrGet();
|
this.timeoutMapRev = db.createTreeMap("timeoutMapRev_" + peerId.toString()).makeOrGet();
|
||||||
@ -60,7 +59,7 @@ public class StorageMapDB implements Storage {
|
|||||||
|
|
||||||
//set parameter to a reasonable default
|
//set parameter to a reasonable default
|
||||||
public StorageMapDB(Number160 peerId, File path, SignatureFactory signatureFactory) {
|
public StorageMapDB(Number160 peerId, File path, SignatureFactory signatureFactory) {
|
||||||
this(DBMaker.newFileDB(new File(path, "tomp2p")).closeOnJvmShutdown().make(),
|
this(DBMaker.newFileDB(new File(path, "coreDB")).closeOnJvmShutdown().make(),
|
||||||
peerId, path, signatureFactory, 60 * 1000);
|
peerId, path, signatureFactory, 60 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,9 +7,10 @@ import android.util.Log;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import net.tomp2p.connection.RSASignatureFactory;
|
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;
|
||||||
@ -21,7 +22,6 @@ import net.tomp2p.peers.PeerAddress;
|
|||||||
import net.tomp2p.relay.tcp.TCPRelayClientConfig;
|
import net.tomp2p.relay.tcp.TCPRelayClientConfig;
|
||||||
import net.tomp2p.replication.AutoReplication;
|
import net.tomp2p.replication.AutoReplication;
|
||||||
import net.tomp2p.storage.Data;
|
import net.tomp2p.storage.Data;
|
||||||
import net.tomp2p.storage.StorageDisk;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
@ -43,9 +43,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.StorageMVStore;
|
|
||||||
import io.github.chronosx88.influence.helpers.StorageMapDB;
|
import io.github.chronosx88.influence.helpers.StorageMapDB;
|
||||||
import io.github.chronosx88.influence.helpers.actions.NetworkActions;
|
|
||||||
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;
|
||||||
|
|
||||||
@ -85,13 +83,15 @@ public class MainLogic implements IMainLogicContract {
|
|||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
|
StorageMapDB storageMapDB = new StorageMapDB(peerID, context.getFilesDir(), new DSASignatureFactory());
|
||||||
peerDHT = new PeerBuilderDHT(
|
peerDHT = new PeerBuilderDHT(
|
||||||
new PeerBuilder(peerID)
|
new PeerBuilder(peerID)
|
||||||
.ports(7243)
|
.ports(7243)
|
||||||
.start()
|
.start()
|
||||||
)
|
)
|
||||||
.storage(new StorageMVStore(peerID, context.getFilesDir()))
|
.storage(storageMapDB)
|
||||||
.start();
|
.start();
|
||||||
|
Runtime.getRuntime().addShutdownHook(new JVMShutdownHook(storageMapDB));
|
||||||
try {
|
try {
|
||||||
String bootstrapIP = this.preferences.getString("bootstrapAddress", null);
|
String bootstrapIP = this.preferences.getString("bootstrapAddress", null);
|
||||||
if(bootstrapIP == null) {
|
if(bootstrapIP == null) {
|
||||||
|
@ -66,6 +66,4 @@ public class StartChatFragment extends Fragment implements IStartChatViewContrac
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: clear text input
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user