Fixed a few problems:
- some bugs that creeped in when I moved security into its own adapter - improved some DB code as it doesn't work in Android anyway - all entities should be serializable (very useful in Android)
This commit is contained in:
@ -81,7 +81,7 @@ public class InternalContext {
|
||||
streams.add(1L);
|
||||
}
|
||||
|
||||
init(inventory, nodeRegistry, networkHandler, addressRepository, messageRepository, proofOfWorkEngine);
|
||||
init(inventory, nodeRegistry, networkHandler, addressRepository, messageRepository, proofOfWorkEngine, security);
|
||||
}
|
||||
|
||||
private void init(Object... objects) {
|
||||
|
@ -19,9 +19,9 @@ package ch.dissem.bitmessage.entity;
|
||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
||||
import ch.dissem.bitmessage.entity.valueobject.Label;
|
||||
import ch.dissem.bitmessage.factory.Factory;
|
||||
import ch.dissem.bitmessage.ports.Security;
|
||||
import ch.dissem.bitmessage.utils.Decode;
|
||||
import ch.dissem.bitmessage.utils.Encode;
|
||||
import ch.dissem.bitmessage.utils.UnixTime;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
@ -29,7 +29,7 @@ import java.util.*;
|
||||
/**
|
||||
* The unencrypted message to be sent by 'msg' or 'broadcast'.
|
||||
*/
|
||||
public class Plaintext implements Streamable, Serializable {
|
||||
public class Plaintext implements Streamable {
|
||||
private final Type type;
|
||||
private final BitmessageAddress from;
|
||||
private final long encoding;
|
||||
@ -64,6 +64,7 @@ public class Plaintext implements Streamable, Serializable {
|
||||
public static Plaintext read(Type type, InputStream in) throws IOException {
|
||||
return readWithoutSignature(type, in)
|
||||
.signature(Decode.varBytes(in))
|
||||
.received(UnixTime.now())
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -132,6 +133,15 @@ public class Plaintext implements Streamable, Serializable {
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public boolean isUnread() {
|
||||
for (Label label : labels) {
|
||||
if (label.getType() == Label.Type.UNREAD) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void write(OutputStream out, boolean includeSignature) throws IOException {
|
||||
Encode.varInt(from.getVersion(), out);
|
||||
Encode.varInt(from.getStream(), out);
|
||||
|
@ -16,14 +16,13 @@
|
||||
|
||||
package ch.dissem.bitmessage.entity;
|
||||
|
||||
import ch.dissem.bitmessage.ports.Security;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An object that can be written to an {@link OutputStream}
|
||||
*/
|
||||
public interface Streamable {
|
||||
public interface Streamable extends Serializable {
|
||||
void write(OutputStream stream) throws IOException;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import ch.dissem.bitmessage.entity.Streamable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* The payload of an 'object' command. This is shared by the network.
|
||||
|
@ -16,9 +16,10 @@
|
||||
|
||||
package ch.dissem.bitmessage.entity.valueobject;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Label {
|
||||
public class Label implements Serializable {
|
||||
private Object id;
|
||||
private String label;
|
||||
private Type type;
|
||||
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2015 Christian Basler
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ch.dissem.bitmessage.ports;
|
||||
|
||||
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
||||
import ch.dissem.bitmessage.utils.UnixTime;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static ch.dissem.bitmessage.utils.Collections.selectRandom;
|
||||
import static ch.dissem.bitmessage.utils.UnixTime.HOUR;
|
||||
import static java.util.Collections.newSetFromMap;
|
||||
|
||||
public class MemoryNodeRegistry implements NodeRegistry {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MemoryNodeRegistry.class);
|
||||
|
||||
private final Map<Long, Set<NetworkAddress>> stableNodes = new HashMap<>();
|
||||
private final Map<Long, Set<NetworkAddress>> knownNodes = new ConcurrentHashMap<>();
|
||||
|
||||
public MemoryNodeRegistry() {
|
||||
try (InputStream in = getClass().getClassLoader().getResourceAsStream("nodes.txt")) {
|
||||
Scanner scanner = new Scanner(in);
|
||||
long stream = 0;
|
||||
Set<NetworkAddress> streamSet = null;
|
||||
while (scanner.hasNext()) {
|
||||
try {
|
||||
String line = scanner.nextLine().trim();
|
||||
if (line.startsWith("#") || line.isEmpty()) {
|
||||
// Ignore
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("[stream")) {
|
||||
stream = Long.parseLong(line.substring(8, line.lastIndexOf(']')));
|
||||
streamSet = new HashSet<>();
|
||||
stableNodes.put(stream, streamSet);
|
||||
} else if (streamSet != null) {
|
||||
int portIndex = line.lastIndexOf(':');
|
||||
InetAddress inetAddress = InetAddress.getByName(line.substring(0, portIndex));
|
||||
int port = Integer.valueOf(line.substring(portIndex + 1));
|
||||
streamSet.add(new NetworkAddress.Builder().ip(inetAddress).port(port).stream(stream).build());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.warn(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
|
||||
List<NetworkAddress> result = new LinkedList<>();
|
||||
for (long stream : streams) {
|
||||
Set<NetworkAddress> known = knownNodes.get(stream);
|
||||
if (known != null && !known.isEmpty()) {
|
||||
for (NetworkAddress node : known) {
|
||||
if (node.getTime() > UnixTime.now(-3 * HOUR)) {
|
||||
result.add(node);
|
||||
} else {
|
||||
known.remove(node);
|
||||
}
|
||||
}
|
||||
} else if (stableNodes.containsKey(stream)) {
|
||||
// To reduce load on stable nodes, only return one
|
||||
result.add(selectRandom(stableNodes.get(stream)));
|
||||
}
|
||||
}
|
||||
return selectRandom(limit, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offerAddresses(List<NetworkAddress> addresses) {
|
||||
for (NetworkAddress node : addresses) {
|
||||
if (node.getTime() <= UnixTime.now()) {
|
||||
if (!knownNodes.containsKey(node.getStream())) {
|
||||
synchronized (knownNodes) {
|
||||
if (!knownNodes.containsKey(node.getStream())) {
|
||||
knownNodes.put(
|
||||
node.getStream(),
|
||||
newSetFromMap(new ConcurrentHashMap<NetworkAddress, Boolean>())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node.getTime() <= UnixTime.now()) {
|
||||
// TODO: This isn't quite correct
|
||||
// If the node is already known, the one with the more recent time should be used
|
||||
knownNodes.get(node.getStream()).add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
||||
import ch.dissem.bitmessage.utils.Property;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* Handles incoming messages
|
||||
@ -30,6 +31,8 @@ public interface NetworkHandler {
|
||||
|
||||
void stop();
|
||||
|
||||
void synchronize(InetAddress trustedHost, int port, MessageListener listener) throws IOException;
|
||||
|
||||
void offer(InventoryVector iv);
|
||||
|
||||
Property getNetworkStatus();
|
||||
|
@ -16,12 +16,6 @@
|
||||
|
||||
package ch.dissem.bitmessage.utils;
|
||||
|
||||
import ch.dissem.bitmessage.entity.Streamable;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A helper class for working with byte arrays interpreted as unsigned big endian integers.
|
||||
* This is one part due to the fact that Java doesn't support unsigned numbers, and another
|
||||
@ -91,6 +85,8 @@ public class Bytes {
|
||||
if (a < 0) return b < 0 && a < b;
|
||||
if (b < 0) return a >= 0 || a < b;
|
||||
return a < b;
|
||||
// This would be easier to understand, but is (slightly) slower:
|
||||
// return (a & 0xff) < (b & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,6 +117,8 @@ public class Encode {
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public static byte[] bytes(Streamable streamable) throws IOException {
|
||||
if (streamable == null) return null;
|
||||
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
streamable.write(stream);
|
||||
return stream.toByteArray();
|
||||
|
15
domain/src/main/resources/nodes.txt
Normal file
15
domain/src/main/resources/nodes.txt
Normal file
@ -0,0 +1,15 @@
|
||||
[stream 1]
|
||||
|
||||
[2604:2000:1380:9f:82e:148b:2746:d0c7]:8080
|
||||
5.45.99.75:8444
|
||||
75.167.159.54:8444
|
||||
95.165.168.168:8444
|
||||
85.180.139.241:8444
|
||||
158.222.211.81:8080
|
||||
178.62.12.187:8448
|
||||
24.188.198.204:8111
|
||||
109.147.204.113:1195
|
||||
178.11.46.221:8444
|
||||
|
||||
[stream 2]
|
||||
# none yet
|
@ -17,21 +17,21 @@
|
||||
package ch.dissem.bitmessage.entity;
|
||||
|
||||
import ch.dissem.bitmessage.entity.payload.*;
|
||||
import ch.dissem.bitmessage.entity.valueobject.Label;
|
||||
import ch.dissem.bitmessage.exception.DecryptionFailedException;
|
||||
import ch.dissem.bitmessage.factory.Factory;
|
||||
import ch.dissem.bitmessage.utils.TestBase;
|
||||
import ch.dissem.bitmessage.utils.TestUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class SerializationTest {
|
||||
public class SerializationTest extends TestBase {
|
||||
@Test
|
||||
public void ensureGetPubkeyIsDeserializedAndSerializedCorrectly() throws IOException {
|
||||
doTest("V2GetPubkey.payload", 2, GetPubkey.class);
|
||||
@ -75,7 +75,7 @@ public class SerializationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ensurePlaintextIsSerializedAndDeserializedCorrectly() throws IOException, DecryptionFailedException {
|
||||
public void ensurePlaintextIsSerializedAndDeserializedCorrectly() throws Exception {
|
||||
Plaintext p1 = new Plaintext.Builder(MSG)
|
||||
.from(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
|
||||
.to(TestUtils.loadContact())
|
||||
@ -99,4 +99,21 @@ public class SerializationTest {
|
||||
assertArrayEquals(data, out.toByteArray());
|
||||
assertEquals(expectedPayloadType.getCanonicalName(), object.getPayload().getClass().getCanonicalName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ensureSystemSerializationWorks() throws Exception {
|
||||
Plaintext plaintext = new Plaintext.Builder(MSG)
|
||||
.from(TestUtils.loadContact())
|
||||
.to(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
|
||||
.labels(Arrays.asList(new Label("Test", Label.Type.INBOX, 0)))
|
||||
.message("Test", "Test Test.\nTest")
|
||||
.build();
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(out);
|
||||
oos.writeObject(plaintext);
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||
ObjectInputStream ois = new ObjectInputStream(in);
|
||||
assertEquals(plaintext, ois.readObject());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user