Refactored use of the DefaultMessageListener so it's retrieved from the InternalContext

This commit is contained in:
2016-09-12 08:18:30 +02:00
parent a240606909
commit 489b8968e0
15 changed files with 180 additions and 173 deletions

View File

@ -62,16 +62,16 @@ public class BitmessageContext {
private final InternalContext ctx;
private final Labeler labeler;
private final NetworkHandler.MessageListener networkListener;
private final boolean sendPubkeyOnIdentityCreation;
private BitmessageContext(Builder builder) {
if (builder.listener instanceof Listener.WithContext) {
((Listener.WithContext) builder.listener).setContext(this);
}
ctx = new InternalContext(builder);
labeler = builder.labeler;
ctx.getProofOfWorkService().doMissingProofOfWork(30_000); // TODO: this should be configurable
networkListener = new DefaultMessageListener(ctx, labeler, builder.listener);
sendPubkeyOnIdentityCreation = builder.sendPubkeyOnIdentityCreation;
}
@ -89,11 +89,11 @@ public class BitmessageContext {
public BitmessageAddress createIdentity(boolean shorter, Feature... features) {
final BitmessageAddress identity = new BitmessageAddress(new PrivateKey(
shorter,
ctx.getStreams()[0],
NETWORK_NONCE_TRIALS_PER_BYTE,
NETWORK_EXTRA_BYTES,
features
shorter,
ctx.getStreams()[0],
NETWORK_NONCE_TRIALS_PER_BYTE,
NETWORK_EXTRA_BYTES,
features
));
ctx.getAddressRepository().save(identity);
if (sendPubkeyOnIdentityCreation) {
@ -117,9 +117,9 @@ public class BitmessageContext {
}
public List<BitmessageAddress> createDeterministicAddresses(
String passphrase, int numberOfAddresses, long version, long stream, boolean shorter) {
String passphrase, int numberOfAddresses, long version, long stream, boolean shorter) {
List<BitmessageAddress> result = BitmessageAddress.deterministic(
passphrase, numberOfAddresses, version, stream, shorter);
passphrase, numberOfAddresses, version, stream, shorter);
for (int i = 0; i < result.size(); i++) {
BitmessageAddress address = result.get(i);
address.setAlias("deterministic (" + (i + 1) + ")");
@ -130,9 +130,9 @@ public class BitmessageContext {
public void broadcast(final BitmessageAddress from, final String subject, final String message) {
Plaintext msg = new Plaintext.Builder(BROADCAST)
.from(from)
.message(subject, message)
.build();
.from(from)
.message(subject, message)
.build();
send(msg);
}
@ -141,10 +141,10 @@ public class BitmessageContext {
throw new IllegalArgumentException("'From' must be an identity, i.e. have a private key.");
}
Plaintext msg = new Plaintext.Builder(MSG)
.from(from)
.to(to)
.message(subject, message)
.build();
.from(from)
.to(to)
.message(subject, message)
.build();
send(msg);
}
@ -170,17 +170,17 @@ public class BitmessageContext {
ctx.send(msg);
} else {
ctx.send(
msg.getFrom(),
to,
Factory.getBroadcast(msg),
msg.getTTL()
msg.getFrom(),
to,
Factory.getBroadcast(msg),
msg.getTTL()
);
}
}
}
public void startup() {
ctx.getNetworkHandler().start(networkListener);
ctx.getNetworkHandler().start();
}
public void shutdown() {
@ -195,7 +195,7 @@ public class BitmessageContext {
* @param wait waits for the synchronization thread to finish
*/
public void synchronize(InetAddress host, int port, long timeoutInSeconds, boolean wait) {
Future<?> future = ctx.getNetworkHandler().synchronize(host, port, networkListener, timeoutInSeconds);
Future<?> future = ctx.getNetworkHandler().synchronize(host, port, timeoutInSeconds);
if (wait) {
try {
future.get();
@ -271,7 +271,7 @@ public class BitmessageContext {
broadcast.decrypt(address);
// This decrypts it twice, but on the other hand it doesn't try to decrypt the objects with
// other subscriptions and the interface stays as simple as possible.
networkListener.receive(object);
ctx.getNetworkListener().receive(object);
} catch (DecryptionFailedException ignore) {
} catch (Exception e) {
LOG.debug(e.getMessage(), e);
@ -281,8 +281,8 @@ public class BitmessageContext {
public Property status() {
return new Property("status", null,
ctx.getNetworkHandler().getNetworkStatus(),
new Property("unacknowledged", ctx.getMessageRepository().findMessagesToResend().size())
ctx.getNetworkHandler().getNetworkStatus(),
new Property("unacknowledged", ctx.getMessageRepository().findMessagesToResend().size())
);
}
@ -296,6 +296,13 @@ public class BitmessageContext {
public interface Listener {
void receive(Plaintext plaintext);
/**
* A message listener that needs a {@link BitmessageContext}, i.e. for implementing some sort of chat bot.
*/
interface WithContext extends Listener {
void setContext(BitmessageContext ctx);
}
}
public static final class Builder {
@ -429,7 +436,7 @@ public class BitmessageContext {
@Override
public MessagePayload handle(CustomMessage request) {
throw new IllegalStateException(
"Received custom request, but no custom command handler configured.");
"Received custom request, but no custom command handler configured.");
}
};
}

View File

@ -24,7 +24,6 @@ import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
import ch.dissem.bitmessage.exception.DecryptionFailedException;
import ch.dissem.bitmessage.ports.Labeler;
import ch.dissem.bitmessage.ports.NetworkHandler;
import ch.dissem.bitmessage.utils.TTL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -32,21 +31,24 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import static ch.dissem.bitmessage.entity.Plaintext.Status.*;
import static ch.dissem.bitmessage.utils.UnixTime.DAY;
import static ch.dissem.bitmessage.entity.Plaintext.Status.PUBKEY_REQUESTED;
class DefaultMessageListener implements NetworkHandler.MessageListener {
class DefaultMessageListener implements NetworkHandler.MessageListener, InternalContext.ContextHolder {
private final static Logger LOG = LoggerFactory.getLogger(DefaultMessageListener.class);
private final InternalContext ctx;
private final Labeler labeler;
private final BitmessageContext.Listener listener;
private InternalContext ctx;
public DefaultMessageListener(InternalContext context, Labeler labeler, BitmessageContext.Listener listener) {
this.ctx = context;
public DefaultMessageListener(Labeler labeler, BitmessageContext.Listener listener) {
this.labeler = labeler;
this.listener = listener;
}
@Override
public void setContext(InternalContext context) {
this.ctx = context;
}
@Override
@SuppressWarnings("ConstantConditions")
public void receive(ObjectMessage object) throws IOException {

View File

@ -56,6 +56,7 @@ public class InternalContext {
private final CustomCommandHandler customCommandHandler;
private final ProofOfWorkService proofOfWorkService;
private final Labeler labeler;
private final NetworkHandler.MessageListener networkListener;
private final TreeSet<Long> streams = new TreeSet<>();
private final int port;
@ -79,6 +80,7 @@ public class InternalContext {
this.connectionLimit = builder.connectionLimit;
this.connectionTTL = builder.connectionTTL;
this.labeler = builder.labeler;
this.networkListener = new DefaultMessageListener(labeler, builder.listener);
Singleton.initialize(cryptography);
@ -94,7 +96,8 @@ public class InternalContext {
}
init(cryptography, inventory, nodeRegistry, networkHandler, addressRepository, messageRepository,
proofOfWorkRepository, proofOfWorkService, proofOfWorkEngine, customCommandHandler, builder.labeler);
proofOfWorkRepository, proofOfWorkService, proofOfWorkEngine, customCommandHandler, builder.labeler,
networkListener);
for (BitmessageAddress identity : addressRepository.getIdentities()) {
streams.add(identity.getStream());
}
@ -148,6 +151,10 @@ public class InternalContext {
return labeler;
}
public NetworkHandler.MessageListener getNetworkListener() {
return networkListener;
}
public long[] getStreams() {
long[] result = new long[streams.size()];
int i = 0;
@ -178,10 +185,10 @@ public class InternalContext {
long expires = UnixTime.now(+timeToLive);
LOG.info("Expires at " + expires);
final ObjectMessage object = new ObjectMessage.Builder()
.stream(recipient.getStream())
.expiresTime(expires)
.payload(payload)
.build();
.stream(recipient.getStream())
.expiresTime(expires)
.payload(payload)
.build();
if (object.isSigned()) {
object.sign(from.getPrivateKey());
}
@ -201,10 +208,10 @@ public class InternalContext {
long expires = UnixTime.now(TTL.pubkey());
LOG.info("Expires at " + expires);
final ObjectMessage response = new ObjectMessage.Builder()
.stream(targetStream)
.expiresTime(expires)
.payload(identity.getPubkey())
.build();
.stream(targetStream)
.expiresTime(expires)
.payload(identity.getPubkey())
.build();
response.sign(identity.getPrivateKey());
response.encrypt(cryptography.createPublicKey(identity.getPublicDecryptionKey()));
// TODO: remember that the pubkey is just about to be sent, and on which stream!
@ -239,10 +246,10 @@ public class InternalContext {
long expires = UnixTime.now(TTL.getpubkey());
LOG.info("Expires at " + expires);
final ObjectMessage request = new ObjectMessage.Builder()
.stream(contact.getStream())
.expiresTime(expires)
.payload(new GetPubkey(contact))
.build();
.stream(contact.getStream())
.expiresTime(expires)
.payload(new GetPubkey(contact))
.build();
proofOfWorkService.doProofOfWork(request);
}

View File

@ -11,6 +11,7 @@ import ch.dissem.bitmessage.ports.ProofOfWorkRepository.Item;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
@ -42,7 +43,7 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC
for (byte[] initialHash : items) {
Item item = powRepo.getItem(initialHash);
cryptography.doProofOfWork(item.object, item.nonceTrialsPerByte, item.extraBytes,
ProofOfWorkService.this);
ProofOfWorkService.this);
}
}
}, delayInMilliseconds);
@ -71,7 +72,7 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC
final ObjectMessage ack = plaintext.getAckMessage();
messageRepo.save(plaintext);
Item item = new Item(ack, NETWORK_NONCE_TRIALS_PER_BYTE, NETWORK_EXTRA_BYTES,
expirationTime, plaintext);
expirationTime, plaintext);
powRepo.putObject(item);
cryptography.doProofOfWork(ack, NETWORK_NONCE_TRIALS_PER_BYTE, NETWORK_EXTRA_BYTES, this);
}
@ -89,15 +90,20 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC
ctx.getLabeler().markAsSent(plaintext);
messageRepo.save(plaintext);
}
try {
ctx.getNetworkListener().receive(object);
} catch (IOException e) {
LOG.debug(e.getMessage(), e);
}
ctx.getInventory().storeObject(object);
ctx.getNetworkHandler().offer(object.getInventoryVector());
} else {
item.message.getAckMessage().setNonce(nonce);
final ObjectMessage object = new ObjectMessage.Builder()
.stream(item.message.getStream())
.expiresTime(item.expirationTime)
.payload(new Msg(item.message))
.build();
.stream(item.message.getStream())
.expiresTime(item.expirationTime)
.payload(new Msg(item.message))
.build();
if (object.isSigned()) {
object.sign(item.message.getFrom().getPrivateKey());
}

View File

@ -41,7 +41,7 @@ public interface NetworkHandler {
* An implementation should disconnect if either the timeout is reached or the returned thread is interrupted.
* </p>
*/
Future<?> synchronize(InetAddress server, int port, MessageListener listener, long timeoutInSeconds);
Future<?> synchronize(InetAddress server, int port, long timeoutInSeconds);
/**
* Send a custom message to a specific node (that should implement handling for this message type) and returns
@ -57,7 +57,7 @@ public interface NetworkHandler {
/**
* Start a full network node, accepting incoming connections and relaying objects.
*/
void start(MessageListener listener);
void start();
/**
* Stop the full network node.

View File

@ -68,7 +68,7 @@ public class DefaultMessageListenerTest extends TestBase {
when(ctx.getNetworkHandler()).thenReturn(networkHandler);
when(ctx.getLabeler()).thenReturn(mock(Labeler.class));
listener = new DefaultMessageListener(ctx, mock(Labeler.class), mock(BitmessageContext.Listener.class));
listener = new DefaultMessageListener(mock(Labeler.class), mock(BitmessageContext.Listener.class));
}
@Test